なぜ危ないのか
オープンリダイレクトとは、URLパラメータに指定したアドレスに無条件でリダイレクトする処理のことだ。例えば`https://example.com/redirect?url=https://attacker.com`のようなURLを作ると、ユーザーは正規ドメインのリンクをクリックしているつもりが攻撃者のサイトに飛ばされる。AIが生成するSPA風のHTMLにはこのパターンが出やすい。
フィッシングメールに自社ドメイン経由のリダイレクトURLが使われると、受信者はドメインを見て安全だと思いクリックしてしまう。実際に国内の金融機関やECサイトでも、こうした経路でフィッシング被害が発生した事例がある。公開前の確認を怠ると、意図せず詐欺の踏み台を提供することになる。
AIはデモとして「ログイン後に元のページへ戻る」機能をURLパラメータで実装することが多い。`?next=/dashboard`や`?redirect=https://...`といったパラメータを受け取り、そのままlocation.hrefに代入する一行が問題の原因になる。この行が含まれているかどうかを公開前に必ず確認する必要がある。
- 相手がログインなしで開ける状態か確認する
- PCとスマホで最低1回ずつ表示を確認する
- 内部情報・個人情報・不要な外部送信が残っていないか見る
- レビュー期限と修正時の差し替え方を決めておく
ソースで見る場所
JavaScriptのコード内で`location.href`・`window.location`・`location.replace`に変数が代入されている箇所を探す。`grep -n 'location.href\|location.replace\|location.assign' output.html`を実行し、右辺が固定文字列ではなくURLパラメータや変数から来ている場合はオープンリダイレクトの疑いがある。
URLパラメータの取得に`URLSearchParams`や`location.search`を使っている箇所も確認する。取得した値を検証せずにそのまま遷移先として使っている場合が問題のパターンだ。特に`new URLSearchParams(location.search).get('redirect')`のような行とlocation.hrefへの代入が近い行に並んでいないか目視確認する。
metaタグの`http-equiv="refresh"`も見落としがちなリダイレクト手段だ。`<meta http-equiv="refresh" content="0;url=`に続くURLが静的かどうかを確認する。PHPやNode.jsのテンプレートが混在している場合、サーバー変数がそこに展開されてオープンリダイレクトになるケースがある。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
安全に共有する設定
オープンリダイレクトを修正する場合は、許可リスト(allowlist)方式が最も確実だ。リダイレクト先として許可するパスをJavaScript内に配列で定義し、パラメータの値が配列に含まれる場合のみ遷移する。外部URLへのリダイレクトが不要であれば、`/`で始まる相対パスのみ許可するチェックを加えるだけで大半のリスクを排除できる。
修正後のHTMLを確認してもらうために外部へ共有する場合は、URLに有効期限と認証を付ける。ギガサイト便のパスワード保護機能を使えば、修正済みのプレビューと修正前の比較をレビュアーに見せながら、不特定多数がアクセスできない状態を保てる。
ブラウザの開発者ツールを使って動作確認する際は、URLバーに`?redirect=https://google.com`を手動で追加してみる。意図しないリダイレクトが発生した場合は修正が必要だ。修正後に同じテストを行い、外部URLへのリダイレクトが発生しないことを確認してから公開する。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
再発防止ルール
AIにリダイレクト機能を含むHTMLを生成させるときは、プロンプトに「リダイレクト先は許可リストで検証し、外部URLへの遷移は禁止する」と明記する。この一文を加えることで、AIが許可リスト方式のコードを出力する確率が上がり、後からの修正コストが減る。
コードレビューのチェックリストに「URLパラメータをlocation系プロパティに直接代入していないか」という項目を追加する。自動化するならESLintのカスタムルールでlocation.hrefへの変数代入を検出する設定を追加するか、SemgrepのJavaScriptルールセットを利用する。
定期的なペネトレーションテストを外部に委託している場合は、オープンリダイレクトをテスト項目に明示的に含めるよう依頼する。AIを使ったHTML生成が普及した現在、この脆弱性の発生頻度は増えているため、テストスコープに含めてもらう価値がある。
- HTML内の外部script・form action・iframeを確認する
- APIキーやトークンらしき文字列がないか検索する
- 画像・CSS・JSのパスが公開後も解決できるか見る
- noindexと認証を混同せず、必要なら両方設定する
よくある質問
オープンリダイレクトが含まれるHTMLをローカルで動かしているだけでも危ないですか?
ローカルのみで外部に公開していない状態では第三者は悪用できない。ただしそのHTMLをGitHubにpushして公開リポジトリに入れると、誰でもコードを参照でき悪用リスクが生まれるため、公開リポジトリへのコミット前にも確認が必要だ。
許可リストに外部URLを含めたい場合(例:特定のパートナーサイトへの誘導)はどうすれば安全ですか?
許可リストの配列をJavaScript内にハードコードし、パラメータ値と完全一致(===)で比較する。前方一致や正規表現を使うとバイパスされやすいため、URLを完全な文字列で列挙する方式が最も安全だ。
Semgrepでオープンリダイレクトを検出するルールはありますか?
`semgrep --config=p/javascript`に含まれる`open-redirect`関連ルールが使える。また`semgrep --config r/javascript.browser.security.open-redirect`で個別ルールを指定することもできる。ただしHTMLに埋め込まれたJSはファイル拡張子が.htmlのため`--lang html`オプションを付ける。