0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Referrer-Policy: no-referrer は、Referer を自分で付けるクライアントには効かない — Chrome ではサイト内の移動も「直接」に落ちた

0
Posted at

自作の小さな Web サーバで、公開ページの応答に Referrer-Policy: no-referrer を付けていました(2026-08-05 から)。
外へのリンクを踏まれたときに、内部の URL を相手に渡さないためです。
(正確には、404 の応答にだけこのヘッダが抜けており、そこが埋まったのは 2026-08-30 です。
下で扱う7件はすべて実在するページ=200 の応答なので、この抜けは7件の説明には効きません)

アクセスの記録は、要求の Referer からホスト名だけを取り、日ごとに数えています。
2026-09-11 までの記録にある参照元は、次のとおりです(記録は 2026-08-06 から)。

参照元 件数
なし(記録上は「直接」) 108
自分のサイトのホスト 7
qiita.com 2

自分のホストが 7件 あります。下の実測のとおり Chrome ならサイト内を移動しても Referer は付かないので、ここは 0 件になるはずでした。
7件は 2026-08-20〜08-22 の3日間(2件・2件・3件)にしかありません。

再現: 1つのローカルサーバで、受け取ったヘッダだけを記録する

127.0.0.1 で立てたサーバが、実際に受け取った要求の Referer を記録します(送る前に横取りはしません)。
ページ a は読み込まれるとすぐ、ページ内の click() で <a> のリンク先 b へ移ります。
別オリジンは 127.0.0.1 と localhost の違いで作りました(ポートは同じでもホストが違えば別オリジンです)。
Chrome は画面なし(--headless=new --dump-dom)で1ページずつ開きました(Windows 11 10.0.26200 / Node v24.18.1)。

a の応答の Referrer-Policy 移動先 b が受け取った Referer
付けない(Chrome の既定) 同じオリジン http://127.0.0.1:8931/default/a.html
付けない(Chrome の既定) 別オリジン http://127.0.0.1:8931/(オリジンだけ)
no-referrer 同じオリジン 無し
no-referrer 別オリジン 無し
same-origin 同じオリジン http://127.0.0.1:8931/same-origin/a.html
same-origin 別オリジン 無し

1行目が陽性対照です(同じ作りで Referer が届く)。これがあるので「無し」を「測れていない」と区別できます。
6通りとも、返ってきた DOM に b のページの <title>b</title> があることを確かめています(移動そのものは起きています)。

もう1つ、Node の fetch で a を取り(応答に Referrer-Policy: no-referrer が付いていることを確認)、
続けて 自分で Referer: http://127.0.0.1:8931/no-referrer/a.html を付けて b を取りました。
b が受け取った Referer は、その付けた値のままでした。

分かったこと

1. 応答のポリシーは、要求を自分で組み立てるクライアントを縛らない

要求に自分で Referer を付ければ、その値はそのままサーバに届きました(Node の fetch はこのヘッダを落としませんでした)。
なお ブラウザの fetch() では Referer は禁止ヘッダ名なので、同じことはできません。
この実測が言えるのはここまでで、「fetch がポリシーを読んで無視した」とは言えません(ポリシーを適用させる場面を1つも作っていないからです)。

冒頭の7件は、この形なら説明がつきます。
記録の順に並べると、2026-08-19 に robots.txt と記事一覧のページを参照元なしで取り、
08-20〜08-22 に 1日2〜3件ずつ、それより前に取ったページの上にあるリンク先 を取っていました。
リンク構造は当時のコミットに固定して機械で突き合わせ、7件とも直前までに取ったページのリンクで説明できました(7/7)。
ただし 1件は、記事一覧のページが自分自身へ張っているリンクで説明したもので、他の6件と同じ重さではありません。

正体は言えません。ユーザーエージェントを保存していないからです。
また記録は日単位の件数なので、同じ日の中の順番は、どのページも件数が1件の日にかぎり、キーの並びを最初に触った順として読めます(この3日間はそうでした)。

2. Chrome では、サイト内の移動でも Referer が消え「直接」に落ちた

表の3行目のとおり、no-referrer は同じオリジンへの移動からも Referer を消します。
つまり冒頭の「直接 108件」には、外から URL を直接開いた人と、自分のサイトの中でページを移っただけの人が、区別できない形で混ざっています。
「自分のホストからの遷移 7件」は、サイト内を移った人の数ではありません。

外へ内部の URL を渡さないことが目的なら、Chrome で <a> を押しての移動について測った範囲では same-origin で足りました(表の5・6行目)。
同じオリジンには付き、別オリジンには付きません。
Chrome の既定(何も付けない)でも、別オリジンにはオリジンだけが渡り、パスは渡りませんでした(表の2行目)。
どれを選ぶかは、何を外に出したくないか次第です。
ただし切り替えると、その日からサイト内の移動が記録に現れるので、それ以前の「直接」の数とは比べられなくなります。

確かめ方

依存パッケージは要りません。私は Chrome と Node v24.18.1 で、次の形の1ファイル(89行)を走らせました。
下のコードは実ファイルの29〜33行目をそのまま貼り、以降を ... で省略しました(// a.html は… の1行だけは説明のために足しています)。

// 抜粋(サーバ側)。case は測定ケース名、host は別オリジンかどうかの根拠
const server = http.createServer((req, res) => {
  const [, policy, file] = req.url.split("/");
  received.push({ case: currentCase, host: req.headers.host, path: req.url, referer: req.headers["referer"] ?? null });
  const headers = { "Content-Type": "text/html; charset=utf-8" };
  if (policy === "no-referrer" || policy === "same-origin") headers["Referrer-Policy"] = policy;
  // a.html はリンクを1本持ち、読み込まれると click() で移る
  ...
});
  • a.html に <a id="next" href="/no-referrer/b.html"> と document.getElementById("next").click() を置く
  • chrome --headless=new --user-data-dir=<空のフォルダ> --no-first-run --virtual-time-budget=3000 --dump-dom http://127.0.0.1:8931/no-referrer/a.html
  • サーバが b.html の要求で受け取った referer を見る

言えないこと

  • 実測は Chrome 1種類・このPC 1台 です。インストール先に版のフォルダが2つあり(151.0.7922.171 / 152.0.7977.83)、どちらが走ったかは確かめていません。Firefox・Safari は見ていません
  • 移動はページ内の click() で、人がマウスで押したものではありません。測ったのは <a> での移動だけで、画像などの副リソース・ダウンロード・fetch/XHR・フォーム送信・リダイレクトは1件も測っていません
  • 測ったのは http → http の loopback 間だけです。既定の strict-origin-when-cross-origin には HTTPS のページから HTTP へ渡すときに Referer を丸ごと落とす分岐がありますが、そこは一度も通していません
  • --virtual-time-budget で打ち切るので、ページの読み込み後に出る付随要求(favicon など)は毎回そろうとは限りません。実際、6通りのうち1通りだけ favicon の要求が届いていません(上の表の結論は、b のページに着いたことで確かめています)
  • 冒頭の7件の正体(人か機械か、何のクライアントか)は分かりません
  • 「直接 108件」のうち何件がサイト内の移動だったかは、この記録からは分けられません

この件を記録していたサーバで、Windows で AI を無人で走らせるときの落とし穴を点検する道具を配っています(無料・依存なし・読むだけで書き換えません・通信しません):

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?