OAuth 2.0 / OIDC 攻撃パターン
OAuth 2.0 と OpenID Connect にお ける代表的な攻撃パターンとその対策をまとめます。
第1部: 認可フロー関連の攻撃
CSRF(Cross-Site Request Forgery)攻撃
攻撃者が被害者のブラウザを使って不正な認可を完了させる攻撃。
攻撃シナリオ:
1. 攻撃者が自分のアカウントで認可フローを開始
2. 認可コードを取得するが、使用しない
3. 被害者に偽の callback URL を踏ませる
https://rp.example.com/callback?code=ATTACKER_CODE
4. 被害者のブラウザで攻撃者の認可コードが使用される
5. 被害者のセッションが攻撃者のアカウントに紐付けられる
結果:
被害者が攻撃者のアカウントで操作
→ 被害者の入力データが攻撃者に送られる
対策:
1. state パラメータを使用
- 認可リクエスト時にラ ンダムな state を生成
- コールバック時に state を検証
- セッションに紐付けて管理
2. PKCE を使用(推奨)
- state に加えて PKCE を使用
- code_verifier はクライアントのみが知っている
認可コード横取り攻撃
悪意のあるアプリケーションが認可コードを傍受する攻撃。
攻撃シナリオ(モバイル):
1. 正規アプリと同じカスタム URL スキームを登録した悪意のアプリ
2. ユーザーが正規アプリで認可を開始
3. 認可コードが悪意のアプリに渡される
4. 悪意のアプリがトークンを取得
┌──────────────┐ code ┌──────────────┐
│ 悪意のアプリ │ ◄─────────── │ Browser │
│ │ │ │
│ │ ── code ────► │ 認可 │
│ │ │ サーバー │
│ │ ◄── token ── │ │
└──────────────┘ └──────────────┘
対策:
1. PKCE を必須にする
- 悪意のアプリは code_verifier を知らない
- トークン交換が失敗する
2. App Links / Universal Links を使用
- ドメイン所有者のみがリンクを登録可能
- カスタム URL スキームより安全
リダイレクト URI 操作
攻撃者が redirect_uri を操作してトークンを盗む攻撃。
攻撃パターン:
1. オープンリダイレクト
redirect_uri=https://rp.example.com/callback?next=https://evil.com
2. パス操作
redirect_uri=https://rp.example.com/callback/../evil
3. サブドメイン
redirect_uri=https://evil.rp.example.com/callback
4. 異なるポート
redirect_uri=https://rp.example.com:8443/callback
対策:
1. 完全一致での検証
- 登録された redirect_uri と完全一致
- パターンマッチングは避ける
2. 正規化後の比較
- URL を正規化してから比較
- パストラバーサルを防止
3. クエリパラメータの扱い
- 登録時にクエリパラメータを禁止
- または完全一致で検証
Mix-Up 攻撃
複数の認可サーバーを使用するクライアントを狙った攻撃。
攻撃シナリオ:
1. クライアントが AS-1 と AS-2 をサポート
2. ユーザーが AS-1 で認可を開始
3. 攻撃者が認可レスポンスを操作
- AS-2 の認可コードを AS-1 のコードとして送信
4. クライアントが AS-1 にトークンリクエスト
5. AS-1 はエラーを返すが、認可コードは漏洩
┌────────┐ AS-2 の code ┌────────┐
│ Client │ ◄────────────── │ 攻撃者 │
│ │ │ │
│ │ ── AS-2 code ─► │ AS-1 │ ← コード漏洩
└────────┘ └────────┘
対策:
1. RFC 9207 の iss パラメータ
- 認可レスポンスに iss を含める
- 期待される issuer と比較
2. state に issuer を含める
- state をデコードして issuer を取得
- レスポンスの送信元と比較
第2部: トークン関連の攻撃
トークン漏洩
アクセストークンやリフレッシュトークンが漏洩する攻撃。
漏洩経路:
1. ログファイル
- トークンがログに記録される
- エラーメッセージにトークンが含まれる
2. Referer ヘッダー
- クエリパラメータにトークンがある場合
- 外部リンクで Referer として送信
3. ブラウザ履歴
- 暗黙的フローでフラグメントにトークン
- URL バーに表示される
4. クライアント側の保存
- localStorage への保存
- XSS で盗まれる可能性
対策:
1. 認可コードフローを使用
- トークンは URL に含まれない
- POST レスポンスで取得
2. DPoP を使用
- トークンを特定の鍵にバインド
- 盗まれても他者は使用できない
3. mTLS を使用
- トークンをクライアント証明書にバインド
- 証明書なしでは使用不可
4. 短い有効期限
- アクセストークンを短く(数分〜数時間)
- 漏洩時の影響を限定
トークン置換攻撃
正当なトークンを別の文脈で不正使用する攻撃。
攻撃シナリオ:
1. Resource A 用のトークンを取得
2. Resource B にトークンを送信
3. Resource B が誤ってトークンを受け入れる
┌────────┐ Token (for A) ┌────────┐
│ 攻撃者 │ ─────────────────► │ Res B │
│ │ │ │
│ │ ◄── 認可成功 ────── │ ✓? │
└────────┘ └────────┘
対策:
1. audience の検証
- JWT の aud クレームを検証
- 自分宛てのトークンのみ受け入れ
2. RFC 8707 Resource Indicators
- リソースごとにトークンを発行
- 別のリソースでは無効
リプレイ攻撃
傍受したトークンやアサーションを再利用する攻撃。
攻撃シナリオ:
1. 攻撃者がネットワークトラフィックを傍受
2. 正当なトークンリクエストを記録
3. 同じリクエストを後で再送
┌────────┐ 傍受したリクエスト ┌────────┐
│ 攻撃者 │ ─────────────────► │ AS │
│ │ │ │
│ │ ◄── Token ──────── │ │
└────────┘ └────────┘
対策:
1. jti クレーム
- JWT に一意識別子を含める
- 使用済み jti をキャッシュ
2. 短い有効期限
- exp を数分に設定
- リプレイの時間窓を短縮
3. TLS
- 通信を暗号化
- 傍受を防止
第3部: クライアント関連の攻撃
クライアント偽装
攻撃者が正規のクライアントになりすます攻撃。
攻撃シナリオ:
1. 公開クライアント(パブリッククライアント)の client_id を取得
2. 攻撃者のアプリで同じ client_id を使用
3. ユーザーを騙して認可させる
対策:
- 機密クライアントはクライアント認証を必須
- パブリッククライアントは PKCE を必須
- redirect_uri の厳格な検証
クライアント認証情報の漏洩
client_secret などの認証情報が漏洩する攻撃。
漏洩経路:
1. ソースコードへのハードコード
- GitHub などで公開
2. 設定ファイル
- .env ファイルの誤公開
3. ログ
- Basic 認証ヘッダーのログ記録
4. サプライチェーン攻撃
- 依存ライブラリ経由での漏洩
対策:
1. private_key_jwt を使用
- client_secret の代わりに非対称鍵
- 秘密鍵は送信されない
2. mTLS を使用
- クライアント証明書で認証
- 証明書の秘密鍵は送信されない
3. シークレット管理
- HashiCorp Vault などを使用
- 環境変数やファイルに直接保存しない
4. ローテーション
- 定期的に client_secret を更新
- 漏洩時の影響を限定
第4部: その他の攻撃
オープンリダイレクター
認可エンドポイントをオープンリダイレクターとして悪用する攻撃。
攻撃シナリオ:
1. 攻撃者が不正な redirect_uri で認可リクエストを作成
https://as.example.com/authorize?
client_id=valid_client
&redirect_uri=https://evil.com/callback
&response_type=code
2. ユーザーが信頼する AS のドメインを見てクリック
3. 認可後、ユーザーが evil.com にリダイレクト
4. フィッシングサイトで認証情報を盗む
対策:
1. redirect_uri の事前登録必須
2. 完全一致での検証
3. ワイルドカードの禁止
4. 不正な redirect_uri はエラーページを表示(リダイレクトしない)