コンテンツにスキップ

DPoP

DPoP (Demonstrating Proof of Possession)

DPoP(RFC 9449)は、アクセストークンをクライアント固有の暗号鍵にバインドするOAuth 2.0セキュリティ拡張です。トークンが傍受されてもリプレイ攻撃を防止できます。

概要

なぜDPoPを使用するのか?

セキュリティ上の利点

  1. トークン窃取からの保護

    • アクセストークンはクライアントの鍵ペアに暗号的にバインド
    • 窃取されたトークンは攻撃者が使用不可(秘密鍵がないため)
    • Bearerトークンの脆弱性を排除
  2. リプレイ攻撃防止

    • 各リクエストに新鮮なDPoP証明が必要(60秒ウィンドウ)
    • 証明ごとに一意のjti(JWT ID)を強制
    • nonce追跡による自動リプレイ検出
  3. エッジネイティブセキュリティ

    • 分散エッジアーキテクチャに最適
    • 共有セッション状態不要
    • JWTを使用したステートレス検証
  4. OAuth 2.1対応

    • DPoPはOAuth 2.1ドラフトの一部
    • OAuthワーキンググループ推奨
    • 業界最高水準のセキュリティ姿勢

ユースケース

  • 金融サービス(FAPI準拠)
  • ヘルスケア(HIPAA準拠トークンセキュリティ)
  • 高セキュリティAPI(政府、銀行、エンタープライズ)
  • モバイルアプリ(安全なトークン保存と使用)
  • ゼロトラストアーキテクチャ

DPoPの仕組み

フロー概要

  1. クライアントが鍵ペアを生成: 非対称鍵ペア(RSA、EC)
  2. クライアントがDPoP証明を作成: 秘密鍵で署名したJWT、jwkヘッダーに公開鍵を含む
  3. クライアントがDPoPヘッダー付きでリクエスト送信: 証明JWTを含むDPoPヘッダー
  4. サーバーがDPoP証明を検証: 署名、クレーム、鮮度、リプレイ保護を検証
  5. サーバーがトークンを鍵にバインド: アクセストークンのcnfクレームにJWKサムプリントを含む
  6. クライアントが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"
}
クレーム説明
jtistring一意識別子(リプレイ防止)
htmstringHTTPメソッド(大文字)
htustringHTTP URL(クエリ/フラグメントなし)
iatnumber発行時刻タイムスタンプ(60秒以内)
athstringアクセストークンハッシュ(アクセストークン使用時に必須)

DPoPを使用したトークンエンドポイント

POST /token

POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: 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_typeDPoPBearerではない)

DPoPを使用したUserInfoエンドポイント

GET /userinfo HTTP/1.1
Authorization: DPoP <access_token>
DPoP: <dpop_proof_jwt>

注: AuthorizationスキームはDPoPBearerではない)

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はドラフト仕様の一部

参考資料