DPoP
DPoP (Demonstrating Proof of Possession)
DPoP(RFC 9449)は、アクセストークンをクライアント固有の暗号鍵にバインドするOAuth 2.0セキュリティ拡張です。トークンが傍受されてもリプレイ攻撃を防止できます。
概要
- RFC: RFC 9449 - OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- ステータス: 完全実装
- 対応エンドポイント:
/token,/userinfo
なぜDPoPを使用するのか?
セキュリティ上の利点
-
トークン窃取からの保護
- アクセストークンはクライアントの鍵ペアに暗号的にバインド
- 窃取されたトークンは攻撃者が使用不可(秘密鍵がないため)
- Bearerトークンの脆弱性を排除
-
リプレイ攻撃防止
- 各リクエストに新鮮なDPoP証明が必要(60秒ウィンドウ)
- 証明ごとに一意の
jti(JWT ID)を強制 - nonce追跡による自動リプレイ検出
-
エッジネイティブセキュリティ
- 分散エッジアーキテクチャに最適
- 共有セッション状態不要
- JWTを使用したステートレス検証
-
OAuth 2.1対応
- DPoPはOAuth 2.1ドラフトの一部
- OAuthワーキンググループ推奨
- 業界最高水準のセキュリティ姿勢
ユースケース
- 金融サービス(FAPI準拠)
- ヘルスケア(HIPAA準拠トークンセキュリティ)
- 高セキュリティAPI(政府、銀行、エンタープライズ)
- モバイルアプリ(安全なトークン保存と使用)
- ゼロトラストアーキテクチャ
DPoPの仕組み
フロー概要
- クライアントが鍵ペアを生成: 非対称鍵ペア(RSA、EC)
- クライアントがDPoP証明を作成: 秘密鍵で署名したJWT、
jwkヘッダーに公開鍵を含む - クライアントがDPoPヘッダー付きでリクエスト送信: 証明JWTを含む
DPoPヘッダー - サーバーがDPoP証明を検証: 署名、クレーム、鮮度、リプレイ保護を検証
- サーバーがトークンを鍵にバインド: アクセストークンの
cnfクレームにJWKサムプリントを含む - クライアントがDPoPバインドトークンを使用: 各リクエストで新鮮なDPoP証明付きでトークンを送信
APIリファレンス
DPoP証明JWT構造
ヘッダー
{ "typ": "dpop+jwt", "alg": "RS256", "jwk": { "kty": "RSA", "n": "...", "e": "AQAB" }}ペイロード(クレーム)
{ "jti": "unique-identifier-123", "htm": "POST", "htu": "https://auth.example.com/token", "iat": 1699876543, "ath": "base64url-hash-of-access-token"}| クレーム | 型 | 説明 |
|---|---|---|
jti | string | 一意識別子(リプレイ防止) |
htm | string | HTTPメソッド(大文字) |
htu | string | HTTP URL(クエリ/フラグメントなし) |
iat | number | 発行時刻タイムスタンプ(60秒以内) |
ath | string | アクセストークンハッシュ(アクセストークン使用時に必須) |
DPoPを使用したトークンエンドポイント
POST /token
POST /token HTTP/1.1Content-Type: application/x-www-form-urlencodedAuthorization: Basic <base64(client_id:client_secret)>DPoP: <dpop_proof_jwt>
grant_type=authorization_code&code=abc123...&redirect_uri=https://myapp.example.com/callbackレスポンス:
{ "access_token": "eyJhbGciOiJSUzI1NiJ9...", "token_type": "DPoP", "expires_in": 3600, "id_token": "eyJhbGciOiJSUzI1NiJ9...", "refresh_token": "eyJhbGciOiJSUzI1NiJ9..."}注: token_typeはDPoP(Bearerではない)
DPoPを使用したUserInfoエンドポイント
GET /userinfo HTTP/1.1Authorization: DPoP <access_token>DPoP: <dpop_proof_jwt>注: AuthorizationスキームはDPoP(Bearerではない)
BearerとDPoPの比較
Bearerトークン(従来方式)
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...- トークンを持っている人なら誰でも使用可能
- 窃取されたトークンは完全に使用可能
- 暗号バインディングなし
DPoPトークン(セキュア)
Authorization: DPoP eyJhbGciOiJSUzI1NiJ9...DPoP: <proof_jwt>- トークンはクライアントの秘密鍵にバインド
- 窃取されたトークンは秘密鍵なしでは使用不可
- 所有証明の暗号的証明
セキュリティ考慮事項
鍵ペア管理
- 強力な鍵を生成(RSA 2048+またはEC P-256+)
- 秘密鍵を安全に保存(セキュアエンクレーブ、暗号化ストレージ)
- 秘密鍵を送信しない
- 定期的に鍵をローテーション
DPoP証明の鮮度
iat検証に60秒ウィンドウ- 各
jtiは一度だけ使用可能 - リクエストごとに新しい証明を生成
サポートされるアルゴリズム
- RS256, RS384, RS512(RSA)
- ES256, ES384, ES512(ECDSA)
- PS256, PS384, PS512(RSA-PSS)
noneおよび対称アルゴリズムは拒否
エラーレスポンス
{ "error": "invalid_dpop_proof", "error_description": "DPoP証明の署名検証に失敗しました"}{ "error": "use_dpop_nonce", "error_description": "DPoP証明のjtiは既に使用されています(リプレイ攻撃検出)"}準拠
- FAPI 2.0: トークンバインディングにDPoP推奨
- OAuth 2.1: DPoPはドラフト仕様の一部