要約
- DPoPでは、アクセストークンの文字列を持つだけでは足りない。提示者は、トークンに結び付いた公開鍵に対応する秘密鍵を使い、要求ごとに新しい証明を作る必要がある。
- 証明が拘束するのは、HTTPメソッド、クエリーとフラグメントを除く対象URI、生成時刻、証明識別子、トークンのハッシュ、必要に応じたサーバーnonceである。要求全体への署名でも、操作への許可でもない。
- 資源サーバーには、発行者、audience、有効期間、失効、scopeの検証、分散した再送状態の調整、外向きURIの復元、そして主体・クライアント・資源・操作・現在状態に対する最終認可が残る。
盗まれた文字列が足りなくなる瞬間
運用担当者が診断ログの中にOAuthアクセストークンを見つけたとする。Bearer方式なら、その文字列を得た者が資格を得る。受け入れる資源サーバーへ到達できれば、失効または期限切れまで、トークンが表す権限を行使できる。
同じ漏えいがDPoP-bound tokenで起きた場合、結果は異なる。攻撃者が別の端末から文字列を送っても、資源サーバーは DPoP 認証スキームのトークンに加え、結び付いた秘密鍵で署名したDPoP proofを要求する。別の鍵で作った証明は公開鍵指紋が一致しない。以前の証明を再送すれば、メソッド、URI、時刻、nonce、または再送記録のいずれかで拒否される。
これがsender constraintの価値である。トークン文字列だけを盗んでも、元の署名能力を持ち出せない限り、完成した資格情報にはならない。
ところが正規のクライアントが同じ操作を試すとき、署名は通り、htm も htu も一致し、ath は提示トークンと一致し、jti は未使用だった。それでも資源サーバーは拒否できる。別サービス向けのトークンだった、読み取りscopeしかなかった、アカウントが停止された、対象の所有者が変わった、一度限りの処理が既に完了した、といった理由である。
DPoPの失敗ではない。一つの層が「結び付いた鍵を今回の要求に使った」と答え、別の層が「その結果を今ここで起こす権限はない」と答えた。健全な設計では、両方が同時に真になり得る。
Bearerの可搬性を一段狭める
RFC 6750 のBearer tokenは、値を所有する者が暗号鍵の所持を示さずに利用できる。TLS、保管、短い有効期限、audience制限は漏えいの確率と影響を下げるが、受入境界内でトークン値が可搬である性質そのものは変えない。
RFC 9449 はアプリケーション層に鍵利用の証明を加える。クライアントは非対称鍵ペアを選び、token endpointに署名済みproofを出す。認可サーバーは発行するaccess tokenやrefresh tokenを公開鍵の JWK Thumbprint に結び付けられる。保護資源への要求では、トークンと新しいproofを一緒に提示し、資源サーバーが同じ鍵かどうかを確認する。
RFC 9700 がsender-constrained token、audience restriction、最小権限を別項目として扱うのは重要である。鍵への結び付きは、別のaudience向けトークンを正しくしない。read scopeをwriteへ増やさない。ユーザーの同意を作らない。発行時には正しかった権限を永続化もしない。
JWK thumbprintは、公鍵の必要なメンバーを規範的に並べてSHA-256で得る決定的な識別子である。鍵を識別するには有用だが、人、会社、端末の健全性、法的委任を識別するものではない。鮮明な暗号識別子ほど、上位の意味を不当に背負わせやすい。
proofの中身と受信側の仕事
DPoP proofはJWSで署名されたJWTである。protected headerには typ として dpop+jwt、許可された非対称 alg、秘密情報を含まない公開 jwk が必要になる。これにより、受信側は一般的なJWTの「署名OK」経路ではなく、DPoP固有の検証規則を選べる。RFC 8725 が求める明示的な型、アルゴリズム、issuer、audienceの分離は、ここでも安全境界になる。
payloadの基本要素は、HTTPメソッドを表す htm、対象URIを表す htu、生成時刻 iat、衝突が無視できるほど予測困難に作る jti である。アクセストークンを使う要求では、さらにトークン値そのもののSHA-256ハッシュ ath を含める。サーバーが DPoP-Nonce を返した後なら、その発行者のnonceも次のproofに入れる。
ath は、一つのproofを別のトークンと組み替える攻撃を防ぐ。同じ証明鍵で別ユーザー向けに発行されたトークンであっても、値が違えば一致しない。nonceは、攻撃前に大量のproofを作り置く価値を下げ、サーバーが最近選んだ値に署名能力が応答したことを示せる。
ただし、claimが並んでいるだけでは何も実行されない。受信側はDPoP headerの重複、壊れたJWT、型の違い、許可外のアルゴリズム、無効な署名、秘密鍵入りJWKを拒否する。そのうえで、現在のメソッドとURI、許容時刻、ath、token-bound thumbprint、nonce規則を実際に比較する必要がある。正しい名詞を含むproofは、正しく検証されたproofと同義ではない。
三本の結び付きを混同しない
第一はtoken-to-key bindingである。認可サーバーは公開鍵のthumbprintを、一般に cnf.jkt としてトークンへ記録する。資源サーバーは、その値と現在のproofに入った公開鍵から計算した値を一致させる。
第二はproof-to-token bindingである。ath が今回提示するアクセストークンの正確な値へproofを拘束する。token substitutionは防ぐが、issuer、audience、scope、有効期間、失効状態は別に検証しなければならない。
第三はtoken発行前に置けるcode-to-key bindingである。認可要求の dpop_jkt は、authorization codeをクライアントが予定したproof keyに結び付ける。これがなければ、認可コードと交換に必要な他の材料を奪った攻撃者が、自分の鍵でproofを作り、攻撃者側の鍵へ正しく結び付いたトークンを得る余地がある。これはPKCE、client authentication、resource owner authorizationとは別の経路を閉じる。
したがって監査に「PoP enabled」という一つのフラグだけを残しても、どの段階が守られたか分からない。発行、コード交換、資源アクセスを分け、比較した値と結果を残す必要がある。
htu が表す要求は、業務命令より小さい
htm により、GET 用proofを DELETE に転用することは難しくなる。htu により、ある対象のproofを別の対象へ運ぶことも防げる。しかしRFC 9449の htu はqueryとfragmentを除外する。要求本文や任意のHTTP headerにも、基礎DPoPは通常署名しない。
たとえば POST /transfer?account=A と POST /transfer?account=B が同じ htu になる設計なら、proofは口座の違いを拘束しない。JSON bodyにある金額や受取人が変わっても、proofの署名範囲は自動的には変わらない。
これは仕様の隠れた欠陥ではなく、役割の境界である。DPoPはsender constraintであり、HTTP Message Signatures、transaction authorization、application idempotencyの代替ではない。RFC 9110 がHTTPの意味を定めても、query、body、現在のobject stateがどんな結果を生むかはアプリケーションが判断する。
proxyやgatewayでは、URI境界も顕在化する。クライアントが署名した外向きscheme、authority、pathが、TLS終端やpath rewrite後の内部表示と違うことがある。下流が誤った側からURIを再構築すれば正規要求を拒否し、複数候補を安易に許せば受入範囲が広がる。外部request context、信頼するforwarding chain、normalization ruleに責任者が要る。
再送耐性は構文ではなく運用状態
iat と jti はreplay detectionの材料であって、自力で重複を拒否しない。サーバーはproofの許容年齢、clock skew、重複判定のkey、保存期間、状態を共有する受入面を決める。
あるregionが jti を保存しても、別regionへ到達する前に同じproofが通る可能性がある。checkとwriteが原子的でなければ、同時要求が二つとも「未使用」を見る。nonceが固定化されるか、広すぎる範囲で再利用されれば、現在性の証明ではなく儀式になる。
認可サーバーと資源サーバーが発行したnonceは交換可能ではない。複数issuerを扱うクライアントは、どの相手から得た値かを分けて保持する必要がある。
さらに、同じproofの再送を拒否しても、業務がexactly onceになるわけではない。クライアントは応答を失った後、別の jti と新しい署名で再試行できる。二つのproofは正当でも、決済を二度実行してよい理由にはならない。idempotency key、commit record、reconciliationは業務層の責任である。
非抽出鍵でも、正しいコードとは限らない
ブラウザーのnon-extractable keyは、トークンと鍵素材を抜き出して別環境へ持ち去る攻撃を抑えられる。RFC 10017 が示すこの性質は、public clientにとって大きな改善である。
一方、アプリケーションと同じoriginですでに動く悪意あるJavaScriptは、利用可能な署名APIを呼び、現在のsessionから要求を送り、新たな認可flowを開始できる。鍵をエクスポートできないことと、誤ったコードが鍵を使えないことは同じではない。
攻撃者がトークンと秘密鍵の双方を得るか、署名インターフェースを継続的に操作できれば、sender constraintは破られる。hardware-backed keyはcustodyを改善するが、侵害済みclientを信頼できるprincipalに変換しない。
実行経路を通る証拠
IANAには DPoP と DPoP-Nonce のHTTP field、関連OAuth parameterが登録されている。共通名称は相互運用の土台だが、本番環境で同じURIが比較され、replay stateが共有され、resource policyが残ったことまでは証明しない。
証拠は発行から結果までをつなぐべきである。raw tokenや秘密鍵を残さず、proofのprivacy-safe hash、public-key thumbprint、token type、ath 結果、外部と内部の正規化URI、proof age、nonce issuer、replay store結果、token issuerとaudience、scope decision、resource policy version、最終commit identifierを相関できるようにする。
negative testには、鍵なしでコピーしたtoken、正しい鍵と別token、古いproof、同一 jti、間違ったmethod、gateway rewrite、欠落または別issuerのnonce、wrong audience、insufficient scope、停止済みsubject、完了済みone-time operationを含める。一つの緑色バッジより、どこでなぜ拒否したかを説明できる方が強い統制証拠である。
会員向け解説
プロフィールの詳細
適切な会員レベルでログインすると、解説全文と出典メモをご覧いただけます。
Strategic Circle 限定
Strategic Circle
すべての読者に公開されています。参加してログインすると プロフィール解説 を閲覧できます。
Strategic Circle に参加Leadership Alliance 会員限定
Leadership Alliance
対象となる IP 資産の所有者・管理者向けです。ログインすると Leadership Alliance の解説を閲覧できます。
Leadership Alliance に参加
