MS_OAuthDPoP - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
- 戻る(OAuth 2.0 拡張、Financial API (FAPI)、OAuth 2.1)
- OAuth2.0 mTLS(最初の派生)
- Token Binding(廃止の傾向)
- OAuth2.0 DPoP
記名式切符(トークン)作成に関する仕様。
-
TLS に依存せず、アプリケーション・レイヤで処理可能にした
セキュリティ拡張仕様(RFC 9449 として標準化)。 -
フロントエンドから使用可能なプラットフォーム上の
公開鍵・暗号化アルゴリズムを使用する。 -
DPoP = Demonstration of Proof-of-Possession at the Application Layer
-
持参人切符から記名式切符へ切り替えることでよりセキュアにする
(OAuth 2.0 のトークンを参照)。 -
方法としては、OAuth 2.0 のアクセストークンを
特定のクライアント(秘密鍵)に紐づける。 -
このため、Token リクエストと Resource リクエストにおいて、
PoP Proof JWT を使用する。 -
Token Bindingのやりたかったことを
TLS に依存せず実現した後継の位置付け。
- SPA などの Public Clients 全般をターゲットとして仕様が作成されている。
- 名前の通り、アプリケーション・レイヤで、記名式切符を発行することができる。
- 「アプリケーション・レイヤで」とは mTLS と異なり
インフラ・レイヤを必要としないの意味。
※ mTLS も Token Bindingも TLS に依存した設計となっている。
※ ただし、後者はブラウザ・サポートによりインフラ構築不要になる予定だったが、
実現せずに、廃案と成った。
補足(3 方式の比較): 記名式トークンの実現手段は 3 つあったが、
現在残っているのは 2 つである。
mTLS(RFC 8705) Token Binding DPoP(RFC 9449) 依存する層 TLS + PKI TLS アプリ層のみ 必要なもの クライアント証明書 ブラウザの実装 無し ブラウザから使えるか 実質不可 予定だったが頓挫 可能 状態 現役 廃止 現役(推奨) 向く場面 サーバー間・金融基幹 - SPA / モバイル / CLI 「TLS に依存しない」という一点が DPoP の存在意義であり、
Token Bindingが QUIC との相性で頓挫したことへの
直接的な答えになっている。
秘密鍵を何処に保存すりゃいいのか?などの説明が不足している
(明示的な規定を避けている)が、一般的な回答としては、
エクスポート不可の Web Crypto API(extractable: false)で
インメモリ生成するのが推奨。
補足(この「課題」が核心): DPoP の安全性は
**「秘密鍵が盗まれないこと」**に全面的に依存する。
ところが SPA では XSS があれば JavaScript が何でもできてしまう。
保管場所 XSS で盗めるか localStorageに鍵の文字列盗める(意味が無い) CryptoKey(extractable: false)鍵自体は取り出せない 同上 + IndexedDB に永続化 取り出せないが、署名の実行は可能 重要なのは、
extractable: falseでも
「鍵を使って署名させる」ことは XSS から可能という点である。
つまり DPoP は
- トークンを持ち出して別の場所で使う攻撃 → 防げる
- その端末・そのページ内で不正に使う攻撃 → 防げない
XSS 対策の代替にはならない、という理解が必要である。
- PrivateKey(秘密・保持)
- PublicKey(DPoP Proof JWT に埋め込む)
| プラットフォーム | API |
|---|---|
| ブラウザ |
crypto.subtle(Web Crypto API、extractable: false) |
| Node.js | webcrypto.subtle |
| iOS / Android ネイティブ | Secure Enclave / Android Keystore |
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2Iiwiandr...
grant_type=authorization_code&code=xxxxx&...
DPoP Proof JWT の構造。
// Header
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
}
// Payload
{
"htm": "POST", // HTTPメソッド
"htu": "https://server.example.com/token", // エンドポイントURL
"iat": 1623420800, // 発行時刻(リプレイ攻撃対策)
"jti": "unique-id" // 一意なID(リプレイ攻撃対策)
}
// Signature (秘密鍵で署名)補足(
htm/htuが肝): Proof JWT に
HTTP メソッドと URL が含まれ、署名されている点が重要である。これにより、Proof を横取りしても
別のエンドポイントに転用できない(htuが一致しない)。
iatとjtiでリプレイも防ぐ。つまり Proof は「このリクエストのために作られた使い捨ての証明」であり、
リクエストごとに新しく生成する必要がある。
- DPoP Proof JWT の署名を検証
-
htm・htuの一致確認で当該処理を目的としているか確認。 -
jti・iatを用いてリプレイ攻撃チェックを行う。
-
- Access トークンの発行
- 公開鍵のハッシュ(
cnf.jkt)を Access トークンに埋め込む
- 公開鍵のハッシュ(
// アクセストークン(JWT)のペイロードに含まれる
{
"sub": "user123",
"cnf": {
"jkt": "0ZcO...(公開鍵のSHA-256ハッシュ)"
}
}毎回、新しい DPoP Proof JWT を生成する。
GET /resource HTTP/1.1
Authorization: DPoP eyJhbGciOi... ← Bearer ではなく DPoP スキーム
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIs... ← Proof JWT
- Access トークンの
cnf.jkt(公開鍵ハッシュ)を取得 - DPoP Proof の署名を検証
-
htm・htuの一致確認 -
jti・iatを用いてリプレイ攻撃チェック -
DPoP Proof JWT の
jwkのハッシュとcnf.jktとの一致確認
(トークンと鍵の紐づけ確認)
-
補足(
Authorization: DPoPスキームの意味):Bearerではなく
DPoPというスキーム名を使う点も設計上重要である。
- Resource Server はスキーム名を見た時点で「Proof の検証が必要」と判断できる。
- 誤って Bearer トークンとして扱う(=検証を飛ばす)事故を防げる。
逆に言えば、Resource Server が DPoP に対応していないと意味が無い。
Authorization Server だけ対応しても効果が出ない点に注意が要る。
移行メモ(最新化:RFC として標準化された): 元ページは
draft-fett-oauth-dpop-01を参照しているが、
2023年9月に RFC 9449 として標準化された。
内容 RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP) FAPI 2.0 mTLS と DPoP の両方を Sender-Constrained の手段として認める 実装 Keycloak / Okta / Auth0 / Entra ID などが対応を進めている 名称も「Demonstration of Proof-of-Possession at the Application Layer」から
「Demonstrating Proof of Possession」 に整理されている。
-
RFC 9449 - OAuth 2.0 Demonstrating Proof of Possession (DPoP)
https://datatracker.ietf.org/doc/html/rfc9449 -
SPAなClientがトークンを安全に扱えるかもしれない拡張仕様「OAuth2.0 DPoP」とは - r-weblife
https://ritou.hatenablog.com/entry/2019/04/19/070000
Tags: 移行, IT国際標準, 認証基盤, クレームベース認証, OAuth