navigator.hardwareConcurrency 与 deviceMemory 报告什么、为何刻意粗化,以及网站如何借它们识破不合常理的设备声明。
JavaScript 里两行代码,就能让页面大致知道你的设备有多强:有多少个逻辑处理器,以及大约多少内存。单独看,这两个数字都不稀奇;合在一起,访客就被归入某个设备档次:入门手机、办公笔记本、工作站。本文讲清每个值的含义、浏览器如何有意把它们模糊化,以及它们最主要的用途——检查所声称的设备是否可信。
核心要点
navigator.hardwareConcurrency报告可用于运行线程的逻辑处理器数量,浏览器报告的数字可能比机器实际拥有的更小。navigator.deviceMemory报告以 GiB 计的近似内存,向 2 的幂取整,并被限制在由实现自行决定的上下界之内。它是 Chromium 一侧的 API,别指望每个浏览器都有。- 这两个值在设计上都是低熵的。它们的分量来自与屏幕尺寸、GPU、平台的组合,计算方法见指纹熵与匿名集。
- 它们最适合做一致性检查:设备在 User-Agent 里声称一个档次、在这里报出另一个档次,就是自相矛盾。
- BrowserInsight 按浏览器的原样显示这两个值;其机器人检测只做简单的范围检验,并不会拿它们去对照你的 User-Agent。
这两个 API 为什么存在
它们都不是为追踪而设计的,而是让页面适配运行它的设备。
hardwareConcurrency 的用途是确定 Web Worker 线程池的大小。MDN 的 hardwareConcurrency 页面给出的示例正是:每个报告的逻辑处理器对应一个 Worker。设备内存规范 W3C Device Memory 则把它描述为一种“设备档次信号”,用于给低端设备提供更轻量的站点版本,以及归一化性能指标,让同样一次长任务在弱设备和强设备上得到不同的解读。
hardwareConcurrency:是逻辑处理器,不是核心数
MDN 将该值定义为用户计算机上可用于运行线程的逻辑处理器数量,范围从 1 到浏览器可能用到的最大数量。有两点要注意:
- 逻辑的,而非物理的。 一颗每核两线程的四核 CPU 可以报告 8。你看到的数字不是核心数。
- 可能被调低。 MDN 指出,浏览器可以报告更小的数字,以更准确地表示同时能运行多少个 Worker,所以它不是对硬件的绝对度量。我们这里不罗列各浏览器的具体调整规则,因为 MDN 没有写死,而且会变化;请到该页面的兼容性表里查看目标浏览器。
真实机器上的常见取值集中在 4、8、12、16 这类常见数值,所以单看这个数字几乎区分不了什么。读数为 2 和读数为 24 当然也能把访客分开,但只是分成很宽的几大群。
deviceMemory:有意做粗
Device Memory API 的设计本意就是不精确。依据规范和 MDN 的 deviceMemory 页面:
- 该值是物理内存向 2 的幂取整后以 GiB 表示的结果,所以你得到的是 2、4、8 这样的数字,而不是“7.6”。
- 随后会被限制在实现自定的下界和上界之间,目的是不暴露极少见的超低或超高内存规格。规范说明实现可以随时间调整这些界限,且不同设备类型可以不同。MDN 自己的例子假设浏览器不报告低于 2 或高于 32 的值,得到 2、4、8、16 或 32。这只是示例,不是通用规则。
- 它只在安全上下文(HTTPS)中可用。
服务器不运行任何脚本也能收到同一数值,途径是 Sec-CH-Device-Memory 客户端提示。它需要主动开启:服务器须先发送 Accept-CH: Sec-CH-Device-Memory,且 MDN 将该请求头标为实验性。这条请求头路径与其他提示的关系,见 User-Agent Client Hints。
各家支持并不一致。Safari 和 Firefox 不提供 deviceMemory,所以那里缺失该值很正常,会显示为“未知”,绝不当作危险信号。不过“没有这个属性”本身,也会向页面透露一点引擎信息。
两个小数字为何仍然重要
拿一个典型的取值组合,问问有多少访客与你相同。答案是很多,这正是任何一个单独的值都不是好标识符的原因。风险出现在它们与几十种其他信号叠加时,比如屏幕几何、GPU 渲染器和平台;每多一个,人群就被切得更小。匿名集的算法说明少量低熵比特是怎样累加的,浏览器指纹指南则列出了这两项在全部信号中的位置。
它们更重要的用途:一致性
弱标识符也可以是强力的测谎仪。这些值应当与浏览器声称的设备相符:
- 桌面 Windows 的 User-Agent 却报告 2 个逻辑处理器和最低的内存档,对现代机器来说不寻常,但并非不可能。
- 移动端 User-Agent 报告几十个逻辑处理器,或超过任何手机的内存数字,说明可能是模拟或虚拟化环境。
- iPhone 的 User-Agent 却提供了
deviceMemory值就很奇怪,因为 WebKit 不提供这个 API。 - 数百个“不同”的访客拥有完全相同的核心数、内存档和屏幕尺寸,看起来像同一个镜像被克隆了很多份。这正是云手机检测背后的聚合模式。
这些单独都不构成证明,它们会与其他矛盾一起加权,例如指纹硬件错配里不可能的 GPU 与操作系统组合、无头浏览器检测中的自动化线索,以及指纹一致性的总体原则。
隐私工具如何处理
加固模式会把精确的硬件值换成通用值,让群体中的每个人看起来都一样。例如 Firefox 的 resist-fingerprinting 模式会把 navigator.hardwareConcurrency 伪装成固定值;resist-fingerprinting 详解讨论了其中的取舍,包括偶尔会有网站因遇到意外取值而出问题。目标是扩大匿名集,而不是造一个可信的假数:随机编出来的数字可能和真值一样有辨识度。在请求头一侧,浏览器只有在服务器主动开启后才会发送 Sec-CH-Device-Memory,而且该值本来就很粗。
BrowserInsight 实际做了什么
直说两件事。指纹检测按浏览器的原样显示 hardwareConcurrency 和 deviceMemory,API 不存在时显示“未知”。机器人检测页面运行一项 hardware_limit 合理性检查,只判断已有的值是否落在合理范围内(核心数 1 到 64,内存不超过 64 GiB),不会拿它们去对照你的 User-Agent 或 GPU。所有采集都在你的浏览器内完成,不会向服务器发送任何数据。
常见问题
hardwareConcurrency 就是 CPU 核心数吗? 不是。它统计的是逻辑处理器,数量可能是物理核心的两倍,而且浏览器可以报告更小的数字。
为什么我的 deviceMemory 从来不是 6 或 12? 这个值在上报前就向 2 的幂取整,所以介于两档之间的容量会落到相邻的一档。
网站不用 JavaScript 能读到我的内存吗?
只能通过 Sec-CH-Device-Memory 客户端提示,而且前提是服务器用 Accept-CH 提出了请求、你的浏览器也支持。
仅凭这个就能追踪我吗? 单靠它不行。只有与许多其他信号组合,它对追踪者才有用。
结语
hardwareConcurrency 和 deviceMemory 是刻意做得很克制的信号:一个粗略的处理器数量,一个取整后的内存档位。它们的实际价值在于检验所声称的设备是否合理,以及给更大的指纹增加几个比特。你可以在指纹检测里查看自己的浏览器报告了什么,看看其余设置是否讲着同一个故事。


