Webの足跡を消す技術:Refererヘッダーの機密性と最新「Referrer-Policy」完全ガイド
ネットワークエンジニアとして現場に立っていると、奇妙なトラブルに遭遇することがあります。「あるシステムから外部の決済APIに遷移した途端、403エラーが返る」「アクセス解析ツールを見ていると、なぜか社内ポータルの完全なURLが外部サイトに漏れ出している」。
犯人は、いつも静かにHTTPリクエストのヘッダーに隠れている、あの小さな文字列です。そう、`Referer`ヘッダーです。
スペルが`Referrer`ではなく`Referer`という歴史的かつ致命的なタイポを抱えたまま、このヘッダーはHTTP/1.1の時代から私たちのWebブラウジングの「足跡」を伝え続けてきました。しかし、現代のプライバシー保護とセキュリティの文脈において、この「おせっかいな親切心」は時に重大なリスクとなります。
今回は、実務でWeb API設計やインフラ運用に携わるエンジニアの皆さんに向けて、`Referer`の仕様の深部、通信の裏側、そして意図せぬ情報漏洩を防ぐための`Referrer-Policy`の実践的な設定術を、現場の知見を交えて徹底解説します。
—
1. `Referer`ヘッダーとは何か?(RFC 7231が定める仕様と歴史)
`Referer`ヘッダーは、ユーザーエージェント(ブラウザなど)が「今リクエストしているリソースに到達する前に、どのページにいたか(リンク元)」のURIをサーバーに通知するためのものです。
RFC 7231(HTTP/1.1: Semantics and Content)では、以下のように定義されています。
> The “Referer” header field allows the user agent to specify a URI reference for the resource from which the target URI was obtained.
なぜプライバシーリスクになるのか?
例えば、ユーザーが社内の秘密裏に進行しているプロジェクト管理システム(例:`https://internal.example.com/project/secret-alpha/settings`)にアクセスし、そのページ内にある外部のCDN上の画像やウィジェットをクリック、あるいは読み込んだとします。
このとき、ブラウザは外部サーバーに対して自動的に以下のようなリクエストを送信します。
GET /widget.js HTTP/1.1
Host: cdn.analytics-vendor.com
Referer: https://internal.example.com/project/secret-alpha/settings
外部CDNのサーバー管理者やアクセス解析ツールには、あなたの「社内の機密URL(パスやクエリパラメータ含む)」が丸見えになります。もしクエリパラメータにセッションIDやユーザー名、検索キーワードなどが含まれていた場合、それらもすべて外部に流出することになります。これが、`Referer`が長年抱えてきたプライバシー上の爆弾です。
—
2. 通信フロー(シーケンス)で見る `Referer` のライフサイクル
実際にブラウザからサーバーへパケットが飛ぶ瞬間を、通信フローの視点から紐解いてみましょう。
[ユーザーのブラウザ] [外部Webサーバー]
│ │
├─ 1. ユーザーが https://A.com/page1 を閲覧 ──────────────> │
│ (リンク: https://B.com/api/item?id=12345 をクリック) │
│ │
├─ 2. リクエスト送信 ──────────────────────────────────────>│
│ GET /api/item?id=12345 HTTP/1.1 │
│ Host: B.com │
│ Referer: https://A.com/page1 │
│ │
│<─ 3. レスポンス返却 (200 OK) ─────────────────────────────┤
│ │
ここで重要なネットワークエンジニア的知見として、`Referer`はTCPレイヤーやTLSレイヤーではなく、HTTP(アプリケーション層)のポリシーによってコントロールされるという点があります。ブラウザが「送信しても安全か、あるいは制限されているか」を判断し、リクエストヘッダーに動的に付与、あるいはマスクして送出しています。
—
3. `Referrer-Policy` による情報のコントロール
この「おせっかいな足跡」を制御するために策定されたのが、W3Cの`Referrer-Policy`仕様です。HTTPレスポンスヘッダー(`Referrer-Policy`)や、HTMLのメタタグ、あるいは各要素の属性(`referrerpolicy`)を使って、送信する情報の粒度をコントロールできます。
実務で必ず押さえておくべき主要なディレクティブを整理しました。
| ポリシー名 | 動作・送信される内容 | ユースケース・実務上の判断 |
| :— | :— | :— |
| `no-referrer` | 一切送信しない(`Referer`ヘッダー自体がつかない) | 極めて機密性の高いページや、外部流出を完全に防ぎたい場合。 |
| `no-referrer-when-downgrade` | HTTPSからHTTPへの遷移時は送信せず、それ以外は完全なURLを送る。 | HTTP/1.1時代のデフォルト。 現在は非推奨になりつつある。 |
| `origin` | オリジン(スキーム+ホスト+ポート)のみ送信する(例: `https://example.com/`) | パスやクエリパラメータを見せずに、「どこから来たか」だけをアナリティクスに伝えたい場合。 |
| `origin-when-cross-origin` | 同一オリジン内なら完全なURL、クロスオリジン(別ドメイン等)ならオリジンのみ。 | セキュリティと利便性のバランスが取れたモダンな設定の一つ。 |
| `same-origin` | 同一オリジン内でのみ完全なURLを送信し、クロスオリジンでは送信しない。 | 社内システムや管理画面など、外部に一切の情報を漏らしたくないクローズドなWebアプリ向け。 |
| `strict-origin-when-cross-origin` | 同一オリジンは完全なURL。クロスオリジンでは、HTTPS→HTTPSの場合のみオリジンを送り、HTTPS→HTTPのダウングレード時は一切送らない。 | 近年のモダンブラウザのデフォルト仕様。迷ったらこれ。 |
| `unsafe-url` | クロスオリジンであっても、プロトコル(HTTP/HTTPS)に関わらず常に完全なURLを送る。 | デバッグ目的以外で使うべきではない(レガシー互換用)。 |
—
4. 実務での設定・実装例:インフラからコードまで
ここからは、実際のインフラ設定やコードレベルで、どのように`Referrer-Policy`を適用し、デバッグするかを見ていきましょう。
A. Webサーバー/CDNでの設定例 (Nginx / Apache)
全社的、あるいはサービス全体で一括してプライバシーポリシーを担保するためには、リバースプロキシやWebサーバーのレイヤーでレスポンスヘッダーを付与するのが最も確実です。
Nginx の設定例
server {
listen 443 ssl;
server_name app.example.com;
# SSL設定などは省略…
# すべてのレスポンスに厳格なReferrer-Policyを付与する
# クロスオリジン時にはオリジン(ドメイン名)のみを伝え、ダウングレード時は送信しない
add_header Referrer-Policy “strict-origin-when-cross-origin” always;
location / {
try_files $uri $uri/ =404;
}
}
インフラエンジニアのTips: `always` パラメーターを忘れないでください。これを付けないと、4xxや5xx系のエラーレスポンス時にカスタムヘッダーがドロップされ、セキュリティスキャンの際に「ヘッダーが欠落している」と検知される原因になります。
—
B. HTML / メタタグでの設定例
特定のWebページ単位、あるいはコンテンツホルダーとして制御したい場合は、HTMLの`
`内にメタタグを挿入します。
社内アナリティクス
—
C. フロントエンド(Fetch API)での制御例
モダンなWebアプリケーション開発において、`fetch()` を使って外部APIにリクエストを投げる際、明示的にReferrerの挙動を制御したい場面があります。
// Fetch APIでのリクエスト送信例
async function fetchExternalData() {
try {
const response = await fetch(‘https://api.external-service.com/v1/data’, {
method: ‘GET’,
// このリクエストにおけるRefererポリシーを明示的に指定
// ‘no-referrer’を指定することで、APIサーバーに一切のリンク元情報を伝えない
referrerPolicy: ‘no-referrer’,
headers: {
‘Content-Type’: ‘application/json’,
‘Authorization’: ‘Bearer YOUR_API_TOKEN’
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(‘取得成功:’, data);
} catch (error) {
console.error(‘API通信エラー:’, error);
}
}
// 実行
fetchExternalData();
—
D. デバッグ・動作確認用ツール(Python / curl)
自分が設計・運用しているシステムが、意図した通りに`Referer`を送信しているか、あるいはブロックできているかを確認するためのデバッグスクリプトです。
Python (Requestsライブラリ) による検証スクリプト
import requests
def test_referer_behavior():
# テスト用のエコーサーバー(受け取ったリクエストヘッダーをそのまま返すパブリックAPI)
target_url = “https://httpbin.org/headers”
# カスタムのRefererを手動で付与してリクエストを送信する
custom_headers = {
“User-Agent”: “NetworkEngineer-DebugTool/1.0”,
“Referer”: “https://secret.internal.net/admin/dashboard?user_id=999″
}
print(f”[] リクエスト送信先: {target_url}”)
print(f”[] 送信すべく設定したReferer: {custom_headers[‘Referer’]}”)
try:
response = requests.get(target_url, headers=custom_headers, timeout=5)
response.raise_for_status()
# サーバー側が実際に受信したヘッダー内容を表示
received_headers = response.json().get(“headers”, {})
server_received_referer = received_headers.get(“Referer”, “Refererヘッダーは検出されませんでした”)
print(“\n— デバッグ結果 —“)
print(f”サーバーが受信したReferer: {server_received_referer}”)
except requests.exceptions.RequestException as e:
print(f”[!] 通信エラーが発生しました: {e}”)
if __name__ == “__main__”:
test_referer_behavior()
curl コマンドでのクイックチェック
開発端末からワンライナーで手軽に挙動を確認したい場合は、`curl` の `-e` オプション(または `-H`)が便利です。
-e オプションで明示的にRefererを指定してhttpbinに送信
curl -i -e “https://example.com/secret-path” https://httpbin.org/headers
—
5. シニアエンジニアからの現場の教訓:トラブルシューティングの勘所
最後に、現場でよくある「Refererにまつわる失敗と教訓」をいくつかシェアしておきます。
1. APIの「403 Forbidden」の罠
画像配信CDNやサードパーティの埋め込みAPIなどが、不正な直リンク(ホットリンク)を防ぐために`Referer`を厳しくチェックしていることがあります。自社のドメイン変更やHTTPS化(HTTPからの移行)を行った際、ポリシーの設定ミスによって正当なユーザーからの画像やAPIリクエストまで弾かれてしまうトラブルが多発します。「突然画像が消えた」という障害に直面したら、まずはブラウザのDevToolsで送信されている`Referer`と、CDN側の許可ドメイン設定を疑ってください。
2. クエリパラメータに個人情報(PII)を含めない設計の重要性
いくら`Referrer-Policy`で制御を試みても、URLの設計自体が貧弱であれば事故は防げません。例えば、GETリクエストのクエリにメールアドレスやトークンを平文で載せる設計(例: `https://example.com/search?q=secret_token_abc123`)をしている場合、他サイトへのリンクを踏んだ瞬間に、そのクエリごとURL全体が外部に流出します。機密情報はURLパスやクエリではなく、POSTボディやヘッダー(Authorization等)でやり取りするRESTの基本原則に立ち返りましょう。
HTTP/1.1という枯れたプロトコルであっても、その上で動くアプリケーションのセキュリティとプライバシーを守るための仕組みは、時代とともに進化しています。`Referer`と`Referrer-Policy`の挙動を正しく理解し、コントロール下置くことは、信頼性の高いインフラを構築する上での必須スキルです。今日のデプロイから、あなたのシステムのヘッダーを見直してみませんか?
コメント