OAuth 2.0のセキュリティ脅威と対策
このドキュメントの目的
OAuth 2.0で発生しうるセキュリティ脅威と、それに対する標準的な対策を理解することが目標です。
主要な脅威と対策
1. Authorization Code横取り攻撃
脅威シナリオ
┌─────────┐ ┌─────────┐ ┌─────────┐
│ ユーザー │ │ IdP │ │ 攻撃者 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ 1. 認証リクエスト │ │
│───────────────>│ │
│ │ │
│ 2. ログイン完了 │ │
│<───────────────│ │
│ │ │
│ 3. Code発行 │ │
│<───────────────│ │
│ │ │
│ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ >│ 4. マルウェアが
│ │ │ Codeを横取り
│ │ │
│ │ 5. Codeでトークン要求
│ │<───────────────│
│ │ │
│ │ 6. Token発行 │
│ │───────────────>│
│ │ │
│ │ 7. なりすましAPI操作
│ │ │
対策: PKCE(Proof Key for Code Exchange)
仕組み:
┌──────────┐ ┌─────────┐
│ クライアント│ │ IdP │
└────┬─────┘ └────┬────┘
│ │
│ 1. code_verifier を生成 │
│ (ランダム文字列) │
│ │
│ 2. code_challenge = SHA256(code_verifier)
│ │
│ 3. 認証リクエスト │
│ + code_challenge │
│──────────────────────────────>│
│ │
│ 4. Authorization Code │
│<──────────────────────────────│
│ │
│ ┌─────────────────────────┐ │
│ │ 攻撃者がCodeを横取りしても │ │
│ │ code_verifierを知らない │ │
│ └─────────────────────────┘ │
│ │
│ 5. Token リクエスト │
│ + code_verifier │
│──────────────────────────────>│
│ │
│ 6. SHA256(code_verifier) │
│ == code_challenge ? │
│ → 一致すればToken発行 │
│ │
│ 7. Access Token │
│<──────────────────────────────│
効果:
- Authorization Codeを横取りしても、code_verifierがないとトークン取得不可
- code_verifierはクライアント内部でのみ保持(横取り不可能)
RFC: RFC 7636 - PKCE
実装ガイド: PKCE実装
2. CSRF攻撃(Cross-Site Request Forgery)
脅威シナリオ
1. 攻撃者が悪意のあるサイトを用意
2. ユーザーが悪意のあるサイトを訪問
3. 悪意のあるサイトが勝手にOAuth Authorization Requestを送信
4. ユーザーが気づかずに認証・認可を承認
5. 攻撃者が用意したredirect_uriにAuthorization Codeが送られる
6. 攻撃者がユーザーのアカウントを乗っ取る
対策: state パラメータ
仕組み:
1. クライアントがstateパラメータ(ランダム文字列)を生成
2. Authorization Requestにstateを含める
3. サーバーがstateをそのまま返す(Callback時)
4. クライアントが元のstateと一致するか検証
効果:
- 攻撃者はstateの値を知らないため、検証で失敗
- リクエストが自分が開始したものであることを確認
3. リプレイ攻撃
脅威シナリオ
1. 攻撃者がID Tokenを盗聴
2. 攻撃者が同じID Tokenを再利用してなりすまし
対策: nonce パラメータ
仕組み:
1. クライアントがnonceパラメータ(ランダム文字列)を生成
2. Authorization Requestにnonceを含める
3. サーバーがID Tokenのnonceクレームに同じ値を設定
4. クライアントがID TokenのnonceとAuthorization Requestのnonceを照合
効果:
- ID Tokenが特定のAuthorization Requestに紐づく
- 盗聴されたID Tokenを別のセッションで再利用できない
OpenID Connect: OpenID Connect Core Section 3.1.2.1
4. トークン漏洩リスク
脅威シナリオ
1. Access Tokenが盗聴される(HTTPSなし、ログ出力等)
2. 攻撃者が盗んだトークンでAPIにアクセス
3. ユーザーになりすましてリソースを操作
対策1: 短い有効期限
推奨値:
- Access Token: 1時間(デフォルト)
- ID Token: 5分(認証完了直後のみ使用)
- Refresh Token: 30日(長期セッション用)
効果:
- トークンが盗まれても、短時間で無効化
- 被害を最小化
対策2: Refresh Token Rotation
仕組み:
1. Refresh Token使用時に新しいRefresh Tokenを発行
2. 古いRefresh Tokenを無効化
3. 同じRefresh Tokenの再利用を検知したら、全トークンを失効
効果:
- Refresh Token盗聴を検知できる
- 盗聴時に被害を最小化
RFC: RFC 6819 - OAuth 2.0 Threat Model
5. Redirect URI検証漏れ
脅威シナリオ
1. 攻撃者が悪意のあるredirect_uriを指定
redirect_uri=https://attacker.com/callback
2. サーバーが検証せずにリダイレクト
3. Authorization Codeが攻撃者のサイトに送られる
4. 攻撃者がトークンを取得
対策: Redirect URI完全一致検証
RFC 6749の要件:
- Authorization RequestとToken Requestのredirect_uriが完全一致
- 事前登録されたredirect_uriのみ許可
- ワイルドカード不可(
https://example.com/*は不可)
実装例:
// 検証ロジック例
if (!registeredRedirectUris.contains(requestRedirectUri)) {
throw new InvalidRedirectUriException("redirect_uri not registered");
}
よくあるミス:
- 部分一致で検証(
startsWithは危険) - 末尾スラッシュの扱い(
/callbackvs/callback/は別物)