玄関の鍵を「だいたい合っていればOK」にしていませんか?OAuthの「リダイレクトURI」で絶対に守るべき鉄則
こんにちは。セキュリティの現場で日々、泥臭いインシデントと格闘しているエンジニアです。
今日は、OAuth 2.0という「便利な鍵の仕組み」を扱う際に、初心者が一番やってしまいがちな「リダイレクトURIの検証ミス」についてお話しします。これ、実はサイバー攻撃者にとって「鍵のかかっていない勝手口」を見つけるようなものなんです。
専門用語は極力使わず、家の防犯に例えて解説していきますね。一歩ずつ、安全な開発の形を学んでいきましょう!
—
1. OAuth 2.0を「合鍵の受け渡し」に例えてみる
OAuth 2.0は、例えば「あるサービス(A)が、あなたのGoogleアカウントのデータを使うときに、パスワードを直接教えずに『一時的な通行証(認可コード)』をもらってやり取りする」仕組みです。
このとき、サービスAがGoogleから「通行証」を受け取るための「帰る場所(リダイレクトURI)」をGoogleに登録しておく必要があります。
- 正しい状態: 「僕の家(`https://myapp.com/callback`)」にだけ帰るように約束している。
- 危険な状態: 「`https://myapp.com` で始まるなら、どこでもいいよ!」と曖昧にしている。
2. なぜ「曖昧な検証」が命取りになるのか?
想像してみてください。あなたは宅配便の配達員に「僕の家の玄関(正しいURI)」へ荷物を届けるよう頼みました。でも、その配達員が「玄関の形が似ていればどこでもいいや」と隣の空き家(攻撃者が用意した偽サイト)に荷物を置いていってしまったらどうなるでしょう?
攻撃者は、あなたの「通行証(認可コード)」をいとも簡単に盗み出せてしまいます。
攻撃のメカニズム
1. 罠を仕掛ける: 攻撃者は、あなたのサービスに似せた偽サイトを作成します。
2. 誘導する: 「ログインして特典をゲットしよう!」とあなたを誘い、OAuthの認証画面へ飛ばします。
3. 横取りする: 認可サーバー(Googleなど)が「認証OK!じゃあ指定された場所にコードを送るよ」と言ったとき、攻撃者が事前に仕込んでおいた「偽の帰る場所」へコードが送信されます。
4. なりすまし完了: 攻撃者はそのコードを使い、あなたのデータにアクセスする権限を手に入れてしまいます。
—
3. 「完全一致」という鉄の掟
この攻撃を防ぐ唯一にして最強の方法は、「リダイレクトURIを完全一致で比較すること」です。
「`https://myapp.com/callback`」と登録したなら、一文字たりとも違ってはいけません。末尾にスラッシュが一つ増えるだけで「別の場所」とみなすくらいの厳格さが必要です。
実装のポイント(サンプルコード)
開発の現場では、以下のように「期待されるURIリスト」を定数で持ち、入力された値と一致するかを厳密にチェックします。
// 許可されたリダイレクトURIのリスト(設定ファイルで管理しましょう)
const ALLOWED_REDIRECT_URIS = [
‘https://myapp.com/callback’,
‘https://myapp.com/oauth/callback’
];
function validateRedirectUri(inputUri) {
// 完全一致での確認(これが最も安全!)
if (!ALLOWED_REDIRECT_URIS.includes(inputUri)) {
throw new Error(“不正なリダイレクトURIです。セキュリティ違反の可能性があります。”);
}
return true;
}
やってはいけないこと:
- `startsWith()` を使って「`https://myapp.com` で始まればOK」と判定する。
- 正規表現で「サブドメインは何でもOK」にする。
これらは、攻撃者が悪意のあるドメインをうまく混ぜ込むことで簡単に突破されてしまいます。
—
4. さらに防犯を強化しよう:Stateパラメーター
リダイレクトURIを厳密にするだけでなく、「Stateパラメーター」という仕組みもぜひ導入してください。
これは、リクエストを送るときに「ランダムな合言葉」を添えておき、戻ってきたときに「その合言葉は正しいか?」を確認する仕組みです。これがあれば、仮にリダイレクト先が少し怪しくても、攻撃者は正しい合言葉を知らないため、処理を完結させることができません。
// ログイン開始時:合言葉(state)を生成してセッションに保存
const state = crypto.randomBytes(16).toString(‘hex’);
sessionStorage.setItem(‘oauth_state’, state);
// 認証後の戻り先で確認
if (receivedState !== sessionStorage.getItem(‘oauth_state’)) {
throw new Error(“通信が改ざんされている可能性があります!”);
}
—
まとめ:セキュリティは「疑うこと」から始まる
OAuthのリダイレクトURI検証は、一見すると面倒な作業に思えるかもしれません。「少し緩くしたほうが便利だし…」という心の隙間を、攻撃者は鋭く突いてきます。
1. リダイレクトURIはホワイトリスト方式で「完全一致」させる。
2. Stateパラメーターで通信の正当性を担保する。
3. 設定ファイルや環境変数で厳密に管理する。
まずはこの3つを徹底するだけで、あなたのアプリケーションの安全性は劇的に向上します。セキュリティは、難しい技術を並べることではなく、「自分の守るべき大切な場所へ、誰が来ようとしているか」を常に確認することから始まります。
一緒に、一歩ずつ堅牢な開発スキルを磨いていきましょうね!

コメント