Chromium 148 Math.tanh OS 指纹识别漏洞
Chromium 148 Math.tanh OS 指纹识别漏洞
Chromium 148 通过 Math.tanh 引入了操作系统级指纹识别
从 Chromium 148 开始,V8 中的 Math.tanh 函数已成为一种可被指纹识别的信号,允许网站识别用户的底层操作系统。这是因为 V8 用 std::tanh 替换了其内置的、可移植的 fdlibm 移植版,而 std::tanh 会调用宿主操作系统的原生数学库 (libm)。
由于不同的操作系统使用不同的数学库——Linux 使用 glibc,macOS 使用 libsystem_m,Windows 使用 UCRT——它们在处理超越函数时会产生略有不同的近似值。对 Math.tanh(0.8) 的单次调用即可区分这三个平台,因为它们在结果的最后几位比特(即最后一位单位,Unit in the Last Place,或 ULP)上存在差异。
操作系统特定的数学特征码
在 Chrome 150 中运行 Math.tanh(0.8),不同平台的运行结果如下:
- Linux (glibc):
0.6640367702678491 - macOS (libsystem_m):
0.664036770267849 - Windows (UCRT):
0.6640367702678489
这为任何伪造 User-Agent 的浏览器带来了矛盾。如果一个浏览器声称自己运行在 macOS 上,但返回了 Linux 特有的数学比特位,反机器人系统可以立即将该会话标记为欺诈。
技术根本原因:libm 分歧
IEEE 754 定义了浮点数的存储方式,但它并不要求 sin、cos 或 tanh 等函数必须进行正确舍入。因此,操作系统厂商会使用不同的 minimax 系数、查找表和归约常数来实现自己的 libm 库,以平衡速度和精度。
V8 的变更
在 Chrome 148 之前,V8 使用内置的 fdlibm 实现,确保了所有平台上的结果完全一致。在 V8 commit c1486295ae5 中的向 std::tanh 的过渡,将计算转移到了宿主的 libm,从而引入了操作系统泄露。
虽然 V8 中的大多数 Math.* 函数仍然是内置的(通过 llvm-libc 或 dbl-64),但 Math.tanh 是目前唯一一个会泄露宿主操作系统的 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) |
| 向量/FFT | 不适用 | 不适用 | Accelerate (Mac) |
泄露表面积的关键发现
- CSS 三角函数: 所有七个 CSS 三角函数都会泄露操作系统,因为 Blink 渲染引擎直接调用宿主
libm。 - Web Audio (macOS): 在 Mac 上,Chrome 使用 Apple 的 Accelerate 框架进行 FFT 和向量数学运算,但对于 DynamicsCompressor 使用标量
libsystem_m。这意味着单个音频图可以泄露两种不同的 Apple 数学特征码。 - WASM: WebAssembly 的数学运算在不同操作系统之间通常是相同的,因为它内置了自己的
libm或使用硬件级算术,尽管它仍可能通过 NaN 规范化泄露 CPU 架构 (ARM vs x86)。
缓解数学指纹识别的策略
简单的噪声注入(向输出添加随机值)是无效的,因为这会产生一个与任何已知操作系统都不匹配的结果,并破坏了确定性,而确定性本身就是一种可检测的信号。
精确的算法重现
为了成功伪造操作系统,实现必须精确地重现目标系统的 libm,包括其特定的 minimax 系数和舍入误差。这需要:
- 逐字系数: 从目标库(例如 Apple 的
libsystem_m)中复制系数的比特模式,而不是使用十进制近似值。 - FMA 控制: 使用显式的融合乘加 (
fma()) 调用并禁用编译器 FMA 缩减 (-ffp-contract=off),以确保结果在不同 CPU 架构(ARM vs x86)上具有比特级的一致性。
库提升 (Library Lifting)
对于 Windows UCRT,可以将真实的 ucrtbase.dll 映射到 Linux 进程内存中。这需要处理 Windows x64 ABI(在 Clang 中使用 ms_abi)以避免堆栈损坏,并强制 CPU 分发标志指向 FMA 路径以匹配现代 Windows 硬件的结果。
社区观点与反论点
技术观察者的讨论突出了关于此漏洞的的几个细微差别:
"Recent glibc 使用了来自 CORE-MATH 的正确舍入 tanh,因此它返回的值与文章中引引用的不同。"
一些用户指出,该漏洞可能对于指纹识别特定浏览器版本范围比单纯识别操作系统更有用,因为大多数用户不会伪造 User-Agent。其他一些人认为,指纹识别向量的普遍性(IP、屏幕分辨率等)使得这一特定的泄露成为在已然受损的隐私景观中一个边际的补充。