タラバガニー設計局stalins.clubNOTE/notes/request-scoped-di-as-security-context

request-scoped DI をセキュリティコンテキストとして使う

認証済みユーザー、tenant、現在の project、認可済み resource のような値は、1リクエストの間だけ有効な依存関係とみなせる。そこで request-scoped DI コンテナを security context の運搬路 として使う設計がある。

NestJS は Scope.REQUEST の provider を用意しており、provider は REQUEST を注入して現在のリクエストへアクセスできる。公式ドキュメントでは multi-tenancy の例として、request header から tenant を決め、それに応じた data source を request-scoped provider として下流へ注入する構成まで示している。これは認可済み tenant/resource を依存グラフへ流す発想とかなり近い。

tanukirpc の Registry も、一般的な IoC container とは形が違うが、リクエスト処理中に利用できる依存関係の束として働く。RouteWithTransformer で Registry を App から ProjectScopeOwnerScope へ変換すると、認可済みリソースをハンドラ入力にすると前提を構造化できる の認可済み値を、その配下のハンドラ全体へ渡せる。

利点は、下流のコードが request.user や route parameter を何度も掘らなくてよくなること、tenant や resource の取得を一度にまとめられること、認可後の状態を再利用しやすいことにある。

一方で、request-scoped DI を広く使うと依存関係が見えにくくなる。とくに「現在の tenant」や「現在の user」がどこから来たのかが関数シグネチャから消える設計では、権限の前提が暗黙化しやすい。また NestJS の公式ドキュメントも request scope はインスタンス生成コストを増やし、依存チェーン上へ scope が波及するため、必要な場合に限ることを勧めている。

そのため security context として DI を使うなら、単に mutable な request-local bag を置くより、型や provider token を権限段階ごとに分け、未認可の context と認可済み context を区別する方が安全性を説明しやすい。

capability と呼べるかは scope に残る authority 次第

より広い object-capability 文献との比較では注意が必要である。Object-Capability は authority を参照の到達可能性で表す では、authority は保持する reference と ambient authority の制約によって決まる。

したがって変換後 Registry が認可済み Project を追加する一方で、元の DB や unrestricted repository を引き継ぐなら、下位 handler は別 project を自由に取得できる。その場合 request-scoped DI は 認可 evidence の運搬路 ではあっても、authority confinement を実現する capability container とはいえない。詳しくは 「認可済みリソース型」は既存研究の直訳ではなく設計上の合成

また request scope は evidence の lifetime を短くできるが、認可後に membership や resource state が変化する問題まで解決しない。revocation / freshness / atomicity は 認可済み値には lifetime と再検証の問題が残る に分離してある。

出典

▸ ノート一覧に戻る