OAuth 2.0 リダイレクトURIの脆弱性が招く「信頼の崩壊」― その深淵と堅牢なアーキテクチャ設計
多くの開発者は、OAuth 2.0を単なる「ログインの簡略化」と考えているかもしれない。しかし、認可フローにおけるリダイレクトURIの検証不備は、単なるバグではない。それは、「信頼の根拠(Trust Anchor)」を外部攻撃者に委ねるという、セキュリティアーキテクチャ上の致命的な背信行為である。
今日は、OAuth 2.0におけるリダイレクトURIの検証不備が、なぜ単なるオープンリダイレクタを超え、トークン窃取によるアカウント乗っ取りという最悪のシナリオに直結するのか、その深層心理を紐解いていく。
—
1. なぜ「ワイルドカード」が地獄への門となるのか
OAuth 2.0の仕様(RFC 6749)において、リダイレクトURIは「あらかじめ登録された完全一致(Exact Match)のURI」であることが大前提だ。しかし、現場では利便性を優先し、正規表現を用いたサブドメインの許可や、パラメータによる動的なリダイレクトを許容してしまう実装が後を絶たない。
攻撃シナリオ:コードの横取り
攻撃者が redirect_uri を巧妙に操作し、自身の管理下にある攻撃者サイトへ認証コード(Authorization Code)を送信させる。これが成功すれば、被害者のセッションは即座にハイジャックされる。
特筆すべきは、「オープンリダイレクタ」がこの脆弱性のトリガーになるケースだ。
信頼されているドメイン(example.com/redirect?url=...)にオープンリダイレクタが存在する場合、認可サーバーがこれを「ホワイトリスト内」と誤認すれば、攻撃者は容易に検閲をすり抜ける。
—
2. 実装レベルでの防衛:ホワイトリストの「厳格」な定義
「厳格な検証」とは、単にリストを照合することではない。パケットレベルでURI構造を解析し、以下の要件を強制する設計が必要だ。
推奨される検証ロジック(擬似コード)
from urllib.parse import urlparse
許可された厳格なリダイレクト先リスト(ハードコードまたは保護された設定ファイル)
ALLOWED_REDIRECT_URIS = {
“https://app.example.com/callback”,
“https://api.example.com/oauth/v2/callback”
}
def validate_redirect_uri(provided_uri):
# 1. 解析:パケット構造上の不整合を排除
parsed = urlparse(provided_uri)
# 2. 完全一致の強制:クエリ文字列やフラグメントの動的付与を拒否
# 攻撃者は正規表現の隙間を突くため、完全一致が唯一の正解である
if provided_uri not in ALLOWED_REDIRECT_URIS:
# ログには詳細を残すが、レスポンスは汎用的なエラーにする
log_security_event(“Invalid Redirect URI Attempt”, provided_uri)
raise SecurityException(“Invalid redirect_uri specified.”)
# 3. プロトコル制限:httpを絶対に許可しない
if parsed.scheme != ‘https’:
raise SecurityException(“Only HTTPS is allowed.”)
return True
—
3. 防御の多層化:トークン窃取を無効化するアーキテクチャ
リダイレクトURIが万が一漏洩しても、攻撃者がトークンを利用できないようにする、あるいは攻撃を検知する「ガードレイル」が必要だ。
PKCE(Proof Key for Code Exchange)の強制
もはやモバイルアプリだけでなく、すべてのクライアントで PKCE を使用すべきだ。code_challenge と code_verifier を組み合わせることで、リダイレクト先でコードを盗まれても、攻撃者はトークンを取得できない。これは OAuth 2.1 における標準仕様であり、議論の余地はない。
セキュリティヘッダーによる制限
リダイレクト先のブラウザで実行されるスクリプトを制御する Content-Security-Policy (CSP) を適切に設定せよ。特に connect-src を絞り込むことで、万が一トークンが流出しても、攻撃者のサーバーへ送信される通信をブロックできる可能性がある。
—
4. セキュリティアーキテクトへの提言:監査の観点
脆弱性診断において、「OAuthのフローを流す」だけでは不十分だ。以下のポイントを泥臭くテストしてほしい。
1. サブドメイン・トラバーサル: https://app.example.com.attacker.com/ といった、FQDNの境界を曖昧にする入力を弾けるか。
2. エンコーディングの悪用: urlencode されたURIをデコードした結果、ホワイトリストの判定を回避できないか(二重エンコーディング攻撃)。
3. パラメータの汚染: リダイレクトURIに余計なクエリパラメータを付与した際、認可サーバーがそれを無視して「正規のもの」と判断するかどうか。
最後に:エンジニアとしての矜持
セキュリティは「魔法の杖」ではない。リダイレクトURIの検証は、地味で退屈な作業かもしれない。しかし、その退屈な「完全一致の検証」を疎かにした瞬間、あなたのサービスは数百万人のユーザーを人質に取られるリスクを背負うことになる。
コードを書くとき、いつも自問自答してほしい。「このリダイレクト先を、私は自分の家族の認証情報を預ける場所として信頼できるか?」。その問いが、あなたのコードを世界で最も堅牢なものに変えるはずだ。
コメント