OAuth 2.0の「リダイレクトURIワイルドカード」という名の地雷原を今すぐ撤去せよ
現場でコードを見ていると、時折「利便性」という名の悪魔に魂を売った設定に出くわす。その筆頭が、OAuth 2.0の認可サーバーにおけるリダイレクトURIのワイルドカード指定だ。
「開発環境と本番環境でURIを分けるのが面倒だから」「サブドメインでクライアントを管理しているから」という理由で https://.example.com/callback のように設定していないか?もしそうなら、君は自分のシステムに「誰でも自由に認可コードを盗み出せる裏口」を掘っているのと同じだ。
今日は、なぜこの設定が致命的なのか、そして現場でどうやって「絶対に破られない」実装を行うのかを、俺の経験を交えて叩き込む。
—
なぜワイルドカードが「致命的」なのか?
OAuth 2.0の認可フローにおいて、リダイレクトURIは「認可コードが届くべき唯一の正当な場所」だ。認可サーバーは、ユーザーが認証に成功した後、このURIに認可コードを付与してリダイレクトする。
もし、ここが https://.example.com/callback となっていたらどうなるか。
攻撃者は、同じドメイン配下で「制御可能なサブドメイン」を用意するだけでいい。例えば、攻撃者が https://attacker.example.com を持っていれば、認可サーバーはそこへ自信満々に認可コードを送り届けてしまう。
攻撃のシナリオ(PoC)
1. 悪意ある細工: 攻撃者は、脆弱なアプリの認可エンドポイントに対し、正規の client_id と、自分のサブドメイン https://attacker.example.com/callback を redirect_uri として指定した認可リクエストを作成する。
2. 認可の実行: ユーザーをそのURLへ誘導し、ログインさせる。
3. コードの流出: 認可サーバーは「お、このサブドメインなら許可リストにあるな」と誤認し、正規のユーザーの code を攻撃者のサーバーに送信する。
4. アカウント乗っ取り: 攻撃者はその code を使い、トークンエンドポイントでアクセストークンを取得。被害者のアカウントが完全に乗っ取られる。
これはXSS(クロスサイトスクリプティング)を組み合わせる必要すらない、「仕様の穴」を突いた極めて高効率な攻撃だ。
—
鉄則:リダイレクトURIは「完全一致」以外ありえない
対策は極めてシンプルだ。「ワイルドカードは一切許可しない」。これに尽きる。
認可サーバー側の実装では、登録されたリダイレクトURIと、リクエストに含まれるURIを「文字列として完全一致するかどうか」で検証しなければならない。
Python (Flask) でのセキュアな実装例
認可サーバー側の検証ロジックは、以下のように書くのが正解だ。
認可サーバーの検証ロジック例
import urllib.parse
DBから取得した、登録済みのホワイトリスト(厳密なURL)
ALLOWED_REDIRECT_URIS = [
“https://app.example.com/callback”,
“https://api.example.com/v1/auth”
]
def validate_redirect_uri(request_uri):
“””
リクエストされたURIがホワイトリストに存在するか厳密にチェックする
“””
if not request_uri:
return False
# 冗長なパスの正規化などは行わず、文字列として完全一致を求める
return request_uri in ALLOWED_REDIRECT_URIS
使用例
request_uri = request.args.get(‘redirect_uri’)
if not validate_redirect_uri(request_uri):
# ここでエラーを返して処理を中断する(ログに不正な試行を記録すること!)
raise SecurityException(“Invalid redirect_uri detected.”)
—
インフラ層での防御(Nginx/WAF)
コードだけでなく、インフラ層でもガードを固めるのがプロの仕事だ。もし何らかの事情で認可サーバーの設定変更が即座にできない場合、WAFでリダイレクトURIのバリデーションをかけることも検討すべきだ。
Nginxでのリクエスト制限例:
リクエストURIにワイルドカード文字が含まれていないかチェックするフィルタのイメージ
location /oauth/authorize {
# 認可コードリクエスト時にredirect_uriが安全な形式か確認
if ($arg_redirect_uri ~ “[\\?]”) {
return 403; # ワイルドカードや正規表現メタ文字が含まれていれば即拒否
}
# 認可サーバーへプロキシ
proxy_pass http://auth_backend;
}
—
最後に、現場の君たちへ伝えたいこと
セキュリティとは「ルールを厳しくすること」ではなく、「攻撃者が入り込める曖昧さを排除すること」だ。
「便利だから」「運用が楽だから」という甘い囁きは、往々にして深刻なインシデントの予兆となる。特にOAuthのような認証・認可の基盤において、妥協はそのまま顧客情報の流出に直結する。
明日、君の担当しているシステムの管理画面を開いてみてくれ。リダイレクトURIの入力欄に “ の文字はないか?もしあれば、今すぐ修正チケットを起票しよう。それが、プロフェッショナルとしての最初の一歩だ。
技術は常に進化するが、攻撃者が狙うのはいつだって「管理が行き届いていない隙間」なんだよ。気を引き締めていこう。
コメント