なぜ「リダイレクト先の指定」が命取りになるのか?— 認可サーバーの守り方
こんにちは。セキュリティの世界へようこそ。今日は、Webサービスで避けては通れない「ログイン」や「SNS連携」の裏側にある、非常に重要で、かつ見落とされがちな「リダイレクトURIの罠」についてお話しします。
「セキュリティ」と聞くと、難解な暗号やファイアウォールを想像するかもしれませんが、実は身近な「家の鍵」と同じです。今日は、泥棒があなたの家の鍵(認可コード)をどうやって盗み出そうとするのか、その手口と対策を一緒に見ていきましょう。
—
1. 「リダイレクトURI」は、あなたの家の「正確な住所」
まず、想像してみてください。あなたは今、信頼できる友だち(GoogleやLINEなどの認可サーバー)に、「私の代わりに玄関の鍵を開けておいて。終わったら、私の家に帰ってくるように伝えてね」とお願いしました。
このとき、「私の家」を指し示す住所が「リダイレクトURI」です。
本来なら、この住所は「https://myapp.com/callback」のように正確に決まっています。しかし、もしこの住所が曖昧だったり、誰でも書き換えられたりしたらどうなるでしょうか?
攻撃者は、あなたの友だちにこう耳打ちします。
「あ、今日から住所が変わったよ。https://attacker.com/steal-dataに送ってあげて!」
友だち(認可サーバー)は何も疑わずに、大切な鍵(認可コード)を攻撃者の家へ運んでしまいます。これが、Webの世界で起きる「オープンリダイレクト脆弱性」の入り口です。
—
2. 攻撃者はどこを狙っているのか?
攻撃者は、あなたが設定したリダイレクトURIの「検証」が甘いところを突いてきます。
例えば、https://myapp.com から始まるURLなら何でも許可してしまうような、ガバガバな設定をしていると危険です。攻撃者は https://myapp.com.attacker.com というような、巧妙に偽装したURLを送り込み、あなたのユーザーのログイン情報を横取りしようとします。
「完全一致」こそが、唯一の正解です。
「だいたい合っていればOK」という考え方は、セキュリティの世界では「穴だらけの玄関」と同じです。リダイレクト先は、一文字のズレも許さない「完全一致」でホワイトリスト化するのが鉄則です。
—
3. 実践!安全なリダイレクト検証のコード例
では、実際にプログラムでどう守ればいいのでしょうか。現場で使える、安全なバリデーションの考え方を紹介します。
ダメな例(やってはいけないこと)
// 注意:これは非常に危険です!
// 文字列が含まれているかだけで判断すると、攻撃の余地が生まれます。
if (redirect_uri.startsWith(“https://myapp.com”)) {
// リダイレクト許可
}
これだと、https://myapp.com.evil-site.com も通ってしまいますよね。
安全な例(推奨)
// ホワイトリストを配列で管理しましょう
const allowedUris = [
“https://myapp.com/callback”,
“https://myapp.com/auth/login”
];
// 完全一致で検証する
if (allowedUris.includes(requestedUri)) {
// 許可する
} else {
// エラーを返し、不正なアクセスとしてログに残す!
throw new Error(“許可されていないリダイレクト先です。”);
}
このように、「あらかじめ許可されたリスト(ホワイトリスト)の中に、全く同じ文字列があるか?」をチェックするだけで、泥棒の侵入を99%防ぐことができます。
—
4. セキュリティヘッダーでさらに守りを固める
コードだけでなく、サーバーの設定でも防壁を作れます。特に「Referrer-Policy」という設定は心強い味方です。
これは、「このページから飛ぶとき、どこから来たのかを相手に伝えていいか?」を制御する設定です。
Referrer-Policy: strict-origin-when-cross-origin
これを設定しておくと、もし万が一リダイレクト先が不審なサイトであっても、ブラウザが機密情報(パスの一部など)を相手に渡さないようガードしてくれます。まるで、家から出るときに、大事なメモを隠してからドアを開けるようなイメージですね。
—
最後に:完璧を目指すより、まずは「疑う」ことから
セキュリティの現場では、「完璧な防御」なんて存在しません。でも、「泥棒が入りにくい家」にすることは誰にでもできます。
1. リダイレクト先は「完全一致」で検証する(あやふやにしない)。
2. 許可リスト(ホワイトリスト)を必ず作る。
3. 不審なリダイレクト要求があったら、迷わずエラーにしてログを吐く。
この3つを意識するだけで、あなたのサービスは格段に安全になります。一歩ずつ、着実に。開発者の皆さんが守ったその一行のコードが、数千、数万人のユーザーの安心を守ることになるんです。
何か少しでも不安なことがあれば、いつでもまた聞きに来てくださいね。一緒に強いサービスを作っていきましょう!
コメント