Chromium 148 Math.tanh OS フィンガープリンティング脆弱性
Chromium 148 Math.tanh OS フィンガープリンティング脆弱性
Chromium 148 が Math.tanh を通じて OS レベルのフィンガープリンティングを導入
Chromium 148 以降、V8 の Math.tanh 関数がフィンガープリンティング可能なシグナルとなり、ウェブサイトがユーザーの基盤となるオペレーティングシステムを特定できるようになりました。これは、V8 がバンドルされたポータブルな fdlibm ポートを廃止し、ホスト OS のネイティブ数学ライブラリ(libm)を呼び出す std::tanh に置き換えたためです。
異なるオペレーティングシステムは異なる数学ライブラリ(Linux は glibc、macOS は libsystem_m、Windows は UCRT)を使用しているため、超越関数の近似が若干異なります。Math.tanh(0.8) を一度呼び出すだけで、結果の最下位ビット(ULP: Unit in the Last Place)が異なるため、これら三つのプラットフォームを区別できます。
OS 固有の数学シグネチャ
Chrome 150 で Math.tanh(0.8) を実行した場合、プラットフォームごとに結果が異なります:
- Linux (glibc):
0.6640367702678491 - macOS (libsystem_m):
0.664036770267849 - Windows (UCRT):
0.6640367702678489
このため、User-Agent を偽装したブラウザが矛盾した結果を返すと、アンチボットシステムは即座にセッションを不正と判断できます。
技術的根本原因: libm の差異
IEEE 754 は浮動小数点数の格納方法を定義していますが、sin、cos、tanh などの関数が正しく丸められることは要求していません。そのため、OS ベンダーは速度と精度のバランスを取るために、異なる minimax 係数、ルックアップテーブル、縮小定数を用いて独自の libm を実装しています。
V8 の変更点
Chrome 148 以前は V8 がバンドルされた fdlibm 実装を使用しており、すべてのプラットフォームで同一の結果が得られていました。V8 のコミット c1486295ae5 で std::tanh に移行したことで、計算がホストの libm に委ねられ、OS 情報が漏洩するようになりました。ほとんどの Math.* 関数は依然として llvm-libc や dbl-64 経由でバンドルされていますが、Math.tanh だけが現在ホスト OS を漏らす唯一の JavaScript 数学関数です。
フィンガープリンティング表面のマッピング
数学を介したフィンガープリンティングは Math.tanh に限りません。ブラウザの各コンポーネントが異なるライブラリを経由して数学呼び出しを行うため、複数の漏洩ベクトルが存在します:
| 操作 | V8 Math.* (JS) |
CSS calc() |
Web Audio |
|---|---|---|---|
sin, cos, tan |
V8 バンドル (安全) | ホスト libm (漏洩) | Accelerate (Mac) / Scalar (Compressor) |
asin, acos, atan, atan2 |
V8 バンドル (安全) | ホスト libm (漏洩) | 使用なし |
tanh |
ホスト libm (漏洩) | なし | 使用なし |
exp, log, pow |
V8 バンドル (安全) | ホスト libm (漏洩) | Scalar (Compressor) |
| Vector/FFT | N/A | N/A | Accelerate (Mac) |
漏洩表面に関する主な所見
- CSS の三角関数: Blink レンダリングエンジンがホスト
libmを直接呼び出すため、7 つすべての CSS 三角関数が OS を漏らします。 - Web Audio (macOS): Mac では Chrome が Apple の Accelerate フレームワークを FFT とベクトル演算に使用しますが、DynamicsCompressor にはスカラー
libsystem_mを使用します。そのため、単一のオーディオグラフで 2 つの異なる Apple 数学シグネチャが漏洩します。 - WASM: WebAssembly の数学は通常 OS 間で同一です。これは独自の
libmをバンドルするか、ハードウェアレベルの演算を使用するためですが、NaN 正規化を通じて CPU アーキテクチャ(ARM vs x86)を漏らすことはあります。
Math フィンガープリンティング緩和策
単純なノイズ注入(出力にランダム値を加える)は効果がありません。なぜなら、既知の OS と一致しない結果となり、決定論的でなくなることで別の検出可能シグナルになるからです。
正確なアルゴリズム再現
OS を偽装するには、対象の libm をビット単位で正確に再現する必要があります。具体的には:
- 係数の逐語的コピー: 対象ライブラリ(例: Apple の
libsystem_m)から係数のビットパターンをそのままコピーし、十進近似を使用しない。 - FMA 制御: 明示的な fused multiply‑add (
fma()) 呼び出しを使用し、コンパイラの FMA 縮約を無効化(-ffp-contract=off)して、CPU アーキテクチャ間でビット同一の結果を保証する(ARM vs x86)。
ライブラリリフティング
Windows UCRT については、正規の ucrtbase.dll を Linux プロセスのメモリにマッピングすることが可能です。その際、Windows x64 ABI(Clang の ms_abi 使用)に対応し、スタック破壊を防ぎ、CPU ディスパッチフラグを FMA パスに強制して、最新 Windows ハードウェアの結果と一致させる必要があります。
コミュニティの見解と反論
技術的観察者間の議論では、以下のようなニュアンスが指摘されています:
"Recent glibc uses the correctly rounded tanh from CORE-MATH, so it returns different values than what's quoted in the article."
一部のユーザーは、この脆弱性は OS の特定よりも特定のブラウザバージョン範囲のフィンガープリンティングに有用であると指摘しています。多くのユーザーは User-Agent を偽装しないためです。また、IP アドレスや画面解像度など既存のフィンガープリンティングベクトルが多数存在するため、この漏洩は既に侵害されたプライバシー環境への僅かな追加に過ぎないという意見もあります。