【実務・中級編】OAuth 2.0におけるリダイレクトURIの厳密な検証とオープンリダイレクト対策 – アプリケーションセキュリティ & 安全な開発防御ガイド

OAuth 2.0の「リダイレクトURI」を甘く見るな――その一行の妥協が、ユーザーを地獄へ引きずり込む

エンジニア諸君、今日もセキュアなコードを書いてるか?

「OAuth 2.0の実装なんてライブラリを使えば一発だよ」なんて考えているなら、今すぐその思考を止めてくれ。ライブラリは道具に過ぎない。その道具をどう設定し、どう境界線を引くか。その設計思想こそが、お前たちの実力を測る尺度だ。

今日は、OAuth 2.0の認可コードフローにおいて、最も初歩的でありながら、いまだに事故が絶えない「リダイレクトURIの検証不備」について話そう。ここを疎かにすると、攻撃者はユーザーの認可コードを鮮やかに盗み出し、アカウントを乗っ取る。

1. なぜ「完全一致」が必要なのか?

認可サーバーは、認証後のユーザーを安全にアプリ側へ戻すためにリダイレクトURIを使う。この時、もしサーバー側が「部分一致」や「正規表現による緩いフィルタリング」を許容していたらどうなるか?

攻撃者は、自らが管理する悪意のあるドメインをリダイレクト先として指定し、認可サーバーを騙す。ユーザーが「許可」ボタンを押した瞬間、認可コードは攻撃者のサーバーへと転送される。

「たった数文字のサブドメインの違いでしょ?」

その油断が、インシデント報告書を書く羽目になる最大の原因だ。RFC 6749でも強く推奨されている通り、リダイレクトURIは「文字列としての完全一致(Exact Matching)」が鉄則だ。

2. 攻撃のPoC(概念実証):背筋が凍る「Open Redirect」の悪用

例えば、クライアントIDが `client_123` で、認可サーバーに以下のリクエストを送るとする。

GET /authorize?response_type=code
&client_id=client_123
&redirect_uri=https://example.com/callback
&scope=read_profile

もし、`example.com` にオープンリダイレクトの脆弱性があったらどうなる? 攻撃者はこう仕掛ける。

`https://example.com/callback?url=https://attacker.com/steal`

認可サーバーが `https://example.com/callback` という前方一致だけを検証していた場合、攻撃者は `redirect_uri` に細工をして、認可コードを自前のサーバーへ送り込ませる。これが「認可コード窃取」のリアルな手口だ。

3. 実践:セキュアなリダイレクトURIの検証コード(Python/Flask)

ライブラリに頼り切るのではなく、ホワイトリストによる厳格な検証を自前で組み込むのが、プロフェッショナルな設計だ。

from flask import Flask, request, abort
import urllib.parse

app = Flask(__name__)

安全なリダイレクト先をハードコードしたホワイトリスト
ALLOWED_REDIRECT_URIS = [
“https://myapp.com/auth/callback”,
“https://myapp.com/auth/callback/v2”
]

def validate_redirect_uri(redirect_uri):
“””
リダイレクトURIの完全一致検証関数
“””
if not redirect_uri:
return False

# URLの正規化を行い、予期せぬエンコードを無効化する
normalized_uri = urllib.parse.unquote(redirect_uri)

# ホワイトリストとの完全一致を強制
return normalized_uri in ALLOWED_REDIRECT_URIS

@app.route(‘/authorize’)
def authorize():
redirect_uri = request.args.get(‘redirect_uri’)

# 検証に失敗した場合は即座に遮断し、ログを残す
if not validate_redirect_uri(redirect_uri):
print(f”セキュリティ警告: 不正なリダイレクトURIが検知されました: {redirect_uri}”)
abort(400, description=”Invalid redirect_uri”)

return “認可フローを開始します…”

4. インフラ層での防御:WAFによる保護

アプリケーションの修正は重要だが、多層防御も忘れてはならない。NginxやWAFの設定で、異常なURLパラメータを弾く設定を加えておくことで、万が一コード側にバグがあっても被害を最小限に抑えられる。

Nginx設定例(リクエストパラメータのサニタイズ)

クエリパラメータに悪意のあるURLが含まれているか簡易チェック
if ($arg_redirect_uri ~ “http(s)?://”) {
# 許可リストに含まれないドメインへのリダイレクトをブロックする例
if ($arg_redirect_uri !~ “^https://myapp\.com/”) {
return 403;
}
}

最後に:エンジニアとしての矜持

リダイレクトURIを「なんとなく動く」設定で放置するのは、玄関の鍵を閉めずに「近所の人なら大丈夫だろう」と祈っているのと同じだ。

私がこれまで見てきた大規模なインシデントの多くは、こうした「仕様の曖昧さ」から侵入を許している。今回紹介した完全一致の徹底と、正規化の処理、そしてホワイトリスト運用。これらを実装するだけで、お前のシステムは格段に硬くなる。

明日のコードレビューで、誰かの `redirect_uri` が緩い実装になっていたら、この記事を突きつけてやってくれ。それが、チームを、そしてユーザーを救うことになるんだ。

何かあればいつでも聞け。セキュリティの戦いに終わりはない。共に戦おう。

コメント

タイトルとURLをコピーしました