指紋は新しい cookie

サードパーティ cookie は廃止されないまま、指紋識別が新たな追跡手段になった。訪問者のニックネームを算出するデモから始まり、指紋のデータ源、情報エントロピーが特徴をビットに換算する仕組み、そして Chrome、Safari、Tor がそれぞれ示す答えまでを追う。

日本語
コピー
xkcd 第 936 期漫画,左边是 Tr0ub4dor&3 这种靠大小写替换凑出来的密码,标着难以记忆;右边是 correct horse battery staple 四个常见词拼成的密码,标着难以猜解;下框写人类二十年努力训练大家使用连自己都记不住的密码

このサイトでは、私が使っている手法であなたを特定することはできない。 JavaScript を無効にしているから、この指紋識別の技はそもそも動かない。だがネットワーク側の手段は今もあなたに有効だ。読み進めて、それが他の人たちに何をしたのかを見てほしい。

今日から、あなたをこう呼ぶ:

… computing…

ページを再読み込みしてみろ。cookie を消せ。VPN につなげ。

それでもあなたは … のままだ。

別の端末やスマホで開けば、ニックネームは変わる。だが同じくらい安定している。

シークレットモードなら違う? 上等だ。だが常に同じ? それは朗報じゃない。

想像してみろ:

あなたが訪れるほとんどのサイトは広告を出して稼ぎ、同時に私のスクリプトをこっそり動かして、あなたが例の … だと私に教えている。それを使ってどの広告を見せるか決められる。だがもっと重要なのは、あなたがそのサイトにアカウントを作っていれば、私はあなたのデータを買い取ると申し出られるということだ——彼らのプライバシーポリシーが共有を許していればの話だが:あなたの名前、行動履歴、AI との会話……

そう時間はかからない。私があなたについて知ることはあなたの友人より多くなる——おそらくあなた自身よりも。

「だから何?」——とあなたは言う。

「隠すものなんてないし。それに興味のある広告のほうがいい……たまにちょうど欲しいものを勧めてくれるし! そもそもデータは匿名化されてるんだろ……」

問題は、これがあなたの話ではまったくないということだ。そして今や広告の話でもない。誰もあなたのことなど気にしていない。だが警察や政府がたまたま気にしたなら、私は喜んで彼らから金を受け取る。

このデータの山を見ても、私には人間が見えない。見えるのはパターンだ。パターンの中からパターンが浮かび上がる。生きた、デジタルのフラクタル——経済、社会、人間心理の状態。21 世紀の水晶玉、しかもシリコン製だ! これが製品だ。

そしてそれは最高入札者に売られる!

ではあなたは何だ? 歯車か? 牛か? ボランティアか?


指紋は新しい cookie

サードパーティ cookie がどれだけ騒がれたか覚えているか? EU がその最も偉大な発明の一つ——同意バナー——を打ち出したほどだ。

EU がテクノロジー企業より速く動くなら、それは企業が傍観していた証拠だ。そしてそのうちの一社が、たまたまブラウザ市場の三分の二を握っている。

この芝居はどう進むのか?

Google に拍手を——地球上最大の広告会社だ!

第一幕:圧力——「プライバシーは私たちにとって極めて重要であり、あらゆる活動の根幹にあります。」

2019 年、cookie はまだ熱かった。だがすでに PR 上の負債になっていた。Safari と Firefox はずっと前からブロックしていた。

一年後、Google は約束した:cookie を廃止する!! そしてプライバシー優先の新王朝を打ち立てる、と。

第二幕:目くらまし——「サードパーティ cookie を廃止する代わりに、まったく新しい体験を提供します」

5 年後:人々の関心はとうに cookie より厄介な問題に奪われ、Google が作り出した仕組み(Privacy Sandbox)はお粗末なもので、独占禁止の懸念まで呼び、誰も使っていない。

「では cookie は残そう。ただしあなたの IP アドレスはマスクする!」( ログイン済みでシークレットモードを有効にしている場合に限る)(** 最終的にこれすら果たされなかった)

第三幕:加速——あなたは今、私たちの広告製品でデバイス指紋を使えます

今や誰が誰かを特定する、より良い方法がある!

指紋識別はどう動くのか?

よし、まともに技術の話をしよう。

あなたがあるサイトを訪れる。ブラウザがサーバーにリクエストを送り、サーバーがブラウザに実行させるコードを返す。

リクエストそのものがすでにあなたの情報をさらしている:どのブラウザを使い、ブラウザの言語は何で、どの OS 上で動き、そしてあなたの IP アドレス——サーバーが応答を返すにはそれが必要だ。そして IP はしばしばあなたの位置を露呈する。

そしてコードが動き出す。

いいか、ブラウジングを安全にする上で、私たちは文明レベルでかなり前進してきた。サイトを訪れるだけでウイルスに感染する、そんな時代はとうに終わった。問題は、安全の定義が人によって違うことだ。最も広い合意は隔離で止まる:あるサイトのコードは他のサイトが保存したデータを見られず、許可なくあなたのファイルや他のアプリも見られない。Chrome と Edge はここで止まる。その先へ進むのが Safari(特に iOS/macOS 26+ 上)と Firefox で、安全の定義をプライバシーへと広げたが、それでも指紋識別からあなたを完全には守れない。Brave と Tor はプライバシー優先ブラウザの先頭を走り、後発には Mullvad Browser がある(Mullvad は私の見るところ、市場で最高の VPN サービスの一つだ)。

コードはあなたのハードウェア上で動き、ハードウェアは測定できる。測定値は一貫していて、かつ独特だ。これといった手はないので、今のところ成熟した方法は二つしかない:

  1. あちこちにノイズを混ぜる。これを farbling と呼び、Brave がそうしている。あなたの指紋を前後で一致させない。
  2. すべてを常に同じに見せる。そうすればブラウザのユーザーを区別できない。Tor と Mullvad はこの道を行く。

よし、指紋を作ってみよう

指紋を組み立てるデータには二つの出所がある:ネットワークリクエストと、コードが動く環境だ。

ネットワークの層を見ると、データはもろいか、ざっくりしているかのどちらかだ:

  • IP アドレス;「理想的な状況」では、一人が常に同じ IP を使うなら、それだけで十分かもしれない。だが現実には人々はモバイル回線で大量に接続し、他人と WiFi を共有し、VPN を使い、あるいは自宅ネットワークの IP が ISP によってローテーションされる。だからもろい。
  • User-Agent や Accept-Language といったヘッダー;あなたのブラウザ、OS、バージョン番号、言語設定をさらす。

デバイス上でコードを実行できるなら、そのハードウェアの特徴を測る方法がある(しかも権限ダイアログは一切不要!)。これらの特徴は驚くほど安定している:

  • GPU;挙動、ベンダー、ドライバ
  • CPU;挙動、ベンダー、スレッド数
  • メモリ容量
  • ディスプレイ情報;解像度、ピクセル比、リフレッシュレート
  • 音声処理
  • デバイスモデル

ソフトウェア側も同じだ。インストール済みフォント、拡張機能、システム情報……

何百万台ものデバイスが最新版の Chrome を動かし、何百万台もの Mac が M4 チップを積み、何百万ものブラウザが言語をフランス語に設定している。

だが、M4 上でフランス語の最新版 Chrome を動かしているデバイスだけを見れば、その数はぐっと減る。さらにハードウェアの測定データを加えれば、ほぼ一意と言っていいレベルまで絞り込める。

指紋は本当に地球上で唯一である必要はない。あなたのサンプルサイズの中で人々を区別できれば十分だ。

郵便番号(IP から推定)、生年月日(どこかのプラットフォームで自分から差し出したもの)、そして性別(どこでも記入する)。この三つを合わせれば、アメリカ人の 60% 以上を一意に識別できる。

変数を一つ足せば、候補のプールはさらに狭まる。

情報エントロピー

Akinatorで遊んだことはあるだろうか。頭の中で人物を思い浮かべると、ランプの精が二十数個の質問をして、答えを当ててくる。指紋識別の仕組みは本質的にこれと同じで、質問に答えるのがブラウザに置き換わっただけだ。情報エントロピーを理解すれば、Akinator の魔法はただの単純なトリックにすぎないと分かる。

盤上の人物を当てるゲームで単純化してみよう。質問は「思い浮かべた人物は男性ですか?」のようなものだ。私が「はい」と答え、盤上の人物の半分が男性なら、候補は半分に絞られる。このとき私の回答はlog₂(100 / 50) = log₂(2) = 1ビットの情報を与えたと言える。候補プールが半分になったからだ。

ある回答がもたらすビット数はその驚異度(surprisal)と呼ばれる。答えが珍しいほど、より多くを教えてくれる。

  • 2 人に 1 人が持つ特徴は 1 ビット(男性である)
  • 8 人に 1 人が持つ特徴は 3 ビット(ひげがある)
  • 128 人に 1 人が持つ特徴は 7 ビット(片目しかない)

驚異度は答えの価値を測り、エントロピーは問いの価値を測る。128 人に 1 人が片目なら、この質問をすると 128 回のうち 127 回は「いいえ」が返ってくる。

回答確率驚異度エントロピーへの寄与
はい1/128log₂(128 / 1) = 7 bits1/128 x 7 = ~0.055
いいえ127/128log₂(128 / 127) = ~0.0113 bits127/128 x 0.0113 = ~0.011

それぞれの起こりうる回答の寄与を足し合わせると、この質問自体は約 0.066 ビットのエントロピーに相当する。つまり、一つの回答から平均して得られるビット数だ。

特徴同士が独立であれば、ビット数をそのまま足すか、比率を掛け合わせればいい。だからひげがあり片目である男性は 11 ビット、2048 分の 1 を意味する。だが Thomas Bayes が教えてくれるように、現実はそう単純ではない。ひげはそれ自体が男性である強い指標であり、男性は片目である可能性も高い。これらの特徴は独立ではないので、ビット数は単純には足せない。

この種の推論には面白い応用がある:

  • 医療診断:人口の 0.01% に影響する既知の疾患について、精度 99% の検査で陽性が出たとする。この結果が誤りである確率は、実際に罹患している確率のおよそ 100 倍だ。もっと証拠が必要だ!

  • 暗号学:ランダムな 4 単語からなるパスワードは、ランダムなキーボード文字 8 文字と同等の強度がある(しかもずっと覚えやすい!)

    xkcd 936

  • 法医学:人口 100 万人の都市で一人に絞り込むには、およそ 20 ビット必要だ。1000 人に 1 人しか一致しない目撃証言は 10 ビットしか与えず、依然として 1000 人の容疑者が残る。

では何ができるのか

自分のブラウザを試してみよう:

  • coveryourtracks.eff.org はあなたの指紋がどれだけ独特かを表示し、各測定データ点のエントロピー値も示してくれる。

Chrome を使っているなら、額に身分証を貼って街を歩いているようなものだ。

Safari と Firefox はある程度の保護を提供するが、高度なトラッカーは依然としてあなたを識別できる。

現時点で、Brave、Tor、Mullvad Browser だけが高度なアンチフィンガープリント保護を実装した主要ブラウザだ。

ブラウザを変えたくないなら、その気持ちは分かる。私自身 Arc の熱心なユーザーだが、残念ながら開発は終了し、プライバシー機能が追加されることは永遠にない。JShelter のような拡張機能もある。ブラウザ API の呼び出しを傍受してフィンガープリントスクリプトを妨害するが、一部のサイトを壊してしまう。Firefox の Resist Fingerprinting 機能も同じ問題を抱えている。

皮肉なことに、プライバシー拡張機能はむしろあなたをより独特にする。使う人が少ないからだ。賢いトラッカーはそれを見分け、拡張機能に妨害された信号を無視し、妨害されていない信号に注目できる。

どんな拡張機能も、ブラウザに組み込まれたエンジンレベルの保護には及ばない。追跡されたくなければ、思い切って乗り換えるしかない。

このページで使っている手法

私はあなたのデバイスに対していくつかの測定を行い、ハッシュを生成しているだけだ。どれか一つでも変化すれば、ハッシュは変わる。専門的なアプリケーションはこれよりはるかに複雑で、単一の変数が変化しても識別の一貫性を保てる。

  1. OfflineAudioContext コンプレッサーで短い音をレンダリングするが、再生はしない。結果に現れるわずかな浮動小数点の差異は、ブラウザの音声エンジンと CPU によって決まる。

    const off = new OfflineAudioContext(1, 5000, 44100);
    // … a 1 kHz triangle wave into a dynamics compressor …
    const data = (await Promise.race([off.startRendering(), timeout])).getChannelData(0);
    let sum = 0;
    for (let i = 4500; i < 5000; i++) sum += Math.abs(data[i]);
    return sum.toFixed(3);
  2. WebGL GPU のベンダーとモデル(バージョン番号は含まない)、GPU とそのドライバが対応する機能、そして小さな三角形をレンダリングした後のピクセルを読み取る。

    const gl = document.createElement('canvas').getContext('webgl');
    const dbg = gl.getExtension('WEBGL_debug_renderer_info');
    return gpuName(gl.getParameter(dbg ? dbg.UNMASKED_RENDERER_WEBGL : gl.RENDERER) || '');
    // "ANGLE (Apple, ANGLE Metal Renderer: Apple M4, Unspecified Version)" -> "apple m4"
    // …
    return fnv1a(new TextEncoder().encode([...(gl.getSupportedExtensions() || []).sort(), ...limits, ...precision].join('|')));
    // …
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, px);
  3. canvas いくつかのフォント、emoji、グラデーションでテキストを描画し、ピクセルを読み戻す。アンチエイリアスとフォントレンダリングは、OS、GPU、フォントによって変わる。

    ctx.font = '15px "Times New Roman", serif';
    ctx.fillText('Sphinx of black quartz 🦊', 4, 22);
    // …
    const data = ctx.getImageData(0, 0, 240, 60).data;
  4. Intl あなたのタイムゾーン、日付と数値のフォーマット。VPN は IP の位置を変えるが、タイムゾーンは変わらない。

    const date = Intl.DateTimeFormat().resolvedOptions();
    // …
    return [date.timeZone, date.locale, date.calendar, date.numberingSystem, hourCycle, (1234567.891).toLocaleString()].join('/');
  5. navigator CPU のコア数、メモリ容量(Chrome のみ)、ブラウザの言語。

    return [navigator.hardwareConcurrency, navigator.deviceMemory, navigator.language].join('/');
  6. crypto.subtle すべての値を SHA-256 でハッシュ化し、そのハッシュ結果が、あなたのニックネームの特徴ひとつと動物一匹を決める。

    const digest = await crypto.subtle.digest('SHA-256', bytes);
    // …
    nickname: stranger || `${pick(TRAITS, hex, 0)} ${pick(ANIMALS, hex, 8)}`,

出典: royfish.dev← ホームへ戻る