navigator.cpuPerformance:性能等级与隐私边界
区分 navigator.cpuPerformance 缺失、零和性能等级,了解 Chrome 152 支持、覆盖设置,以及 CPU 分桶的隐私与推断边界。
BotBrowser Team
navigator.cpuPerformance 是粗粒度的 CPU 性能分类,不是处理器名称、实时利用率读数或身份验证。Chrome 152 将该 API 列为已发布功能。固定版本的 WICG 草案定义了四个正值等级,以及单独表示分类未知的 0;属性缺失则是另一种观察结果。BotBrowser 可以配置文档明确覆盖的核心数信号,但单凭 --bot-cores 设置,不能确定这个独立属性如何报告。当浏览器报告把 CPU 等级、核心数、内存和计时信号放在一起时,需要保留这条边界。
观看视频
本视频为英文音频,围绕上面同一个问题展开:返回的 navigator.cpuPerformance 等级是粗粒度的静态分类,不是实时负载读数。视频把属性缺失、表示未知的数值 0、当前正值等级、无法识别的未来等级和读取失败分开呈现,随后展示草案的核心数映射、由实现决定的型号调整、隐私设计区间、Chrome 有文档记录的覆盖设置,以及在受控夹具中录制的一段 Ubuntu Chrome 读回。它不重建精确核心数、处理器型号或基准分数。音频为英文。
摘要
navigator.cpuPerformance属性缺失、数值0和已报告的等级是不同状态。缺少信息不代表设备属于低性能类别。- 草案的初始映射使用操作系统报告的核心数,并允许由实现定义的 CPU 型号调整。等级不能还原精确核心数或处理器型号。
- 静态等级不会跟随当前 CPU 负载变化。Chrome 文档允许用户和管理员覆盖报告值,因此不能把所有值都当成未经修改的硬件测量。
- 草案指定在安全
Window上下文中暴露属性。Chrome 152 的说明不等于所有浏览器、嵌入式运行环境或 Worker 都支持它。 - 粗分桶减少的是细节,不是硬件信号本身。排查 CPU 等级的支持记录不需要附带无关标识符。
目录
先区分返回状态,再讨论硬件
固定版本的 CPU Performance API 草案为 Navigator 增加了只读的 unsigned short 属性。IDL 声明包含 SecureContext 和 Exposed=Window。这些细节说明接口所属的上下文,不是一张覆盖所有已安装浏览器的兼容表。解释返回值之前,应先确定实际观察了哪个上下文。
| 观察结果 | 来源或采集函数能够支持的解释 | 不能据此确定的事项 |
|---|---|---|
上下文未通过 isSecureContext 检查 | 函数没有继续在该上下文采集 | 设备属于低性能等级 |
| 属性未暴露 | 被检查的 Navigator 中没有该属性 | 缺失原因、某种隐私产品或 CPU 型号 |
数值 0 | API 报告分类未知 | 核心数为零、没有 CPU 或 JavaScript 读取失败 |
从 1 到 4 的整数 | 当前的正值性能等级 | 精确吞吐量、硬件身份或当前利用率 |
大于 4 的正整数 | 当前调用方不认识的未来等级 | 固定版本的 getter 目前确实会返回该值 |
| 读取异常或类型不符合预期 | 采集没有得到预期形式的值 | 一个有效的硬件分类 |
即使仪表盘希望使用一个简短标签,接口暴露与分类状态的区别仍然存在。把 undefined 和 0 都替换成“未知”,会丢失接口是否可用的信息。把它们改成等级 1 更严重,因为这相当于凭空增加了浏览器没有提供的性能判断。这些转换可能在任何硬件推断开始之前,就已经误导了比较。
Window 中的辅助函数可以在不发起网络请求、不运行基准测试的情况下保留区别。下面的分支是采集策略示例,不是某次浏览器运行的输出。安全上下文检查被有意设置为前置条件:在这里返回,表示跳过采集,而不是已经确诊 API 不可用。
function readCpuTier() {
if (!globalThis.isSecureContext) return { state: 'context-skipped' };
if (!('cpuPerformance' in navigator)) return { state: 'not-exposed' };
try {
const tier = navigator.cpuPerformance;
if (!Number.isInteger(tier) || tier < 0 || tier > 65535) {
return { state: 'unexpected-value' };
}
if (tier === 0) return { state: 'unknown' };
if (tier <= 4) return { state: 'tier', tier };
return { state: 'future-tier', tier };
} catch {
return { state: 'read-error' };
}
}
草案当前对 getter 断言的范围是 0 到 4,但性能等级章节同时要求应用兼容后续修订可能增加的等级。保留不认识的正整数是一种向前兼容处理,并不声称现有实现已经返回等级 5。应用可以为这种状态选择保守的功能预设,但诊断记录不应悄悄把它重新标为某个已知等级。
属性检查的作用也小于真实性验证。在页面的 navigator 对象上发现 cpuPerformance,不能证明周围的 JavaScript 环境可信;读取成功也不等于设备通过认证。功能存在性属于能力处理,不应变成账户访问条件,更不能据此宣称浏览器报告证明了谁在操作机器。
草案分类算法及其边界
草案从操作系统报告的核心数开始。其“核心”定义包括操作系统所报告的物理或逻辑执行单元,而不是规定必须使用页面 JavaScript 通过 navigator.hardwareConcurrency 读到的数值。核心数报告分析区分了页面可见报告与底层并行能力。把页面的数值代入下表,不等于重现浏览器基于操作系统数据执行的分类。
| 草案使用的操作系统初始输入 | 初始等级 |
|---|---|
无法取得核心数,或核心数为 0 | 0 |
1 个核心 | 1 |
2 到 4 个核心 | 2 |
5 到 10 个核心 | 3 |
多于 10 个核心 | 4 |
同一章节允许在已知 CPU 型号明显快于或慢于同核心数的典型设备时调整等级。这种调整通常不超过一个等级,需要操作系统提供可靠的型号信息,适用的型号集合则由实现定义。“通常”是来源中的限定,不是所有实现都必须使用同一份调整名单的承诺。
因此,反向映射并不唯一。等级 3 可以来自 5 到 10 核心的初始组,但型号调整也会影响最终分类。即使没有调整,一个包含多个数值的分组也不披露精确核心数。加入调整后,从最终整数推断唯一处理器更加缺乏依据。返回的桶比参与选桶的内部输入包含的信息更少。
WICG 文档链接的参考实现和演示页面被明确标为非规范性内容。示例启发式产生的分类有助于理解算法,但不能证明已安装浏览器使用了相同的型号数据。以假设输入算出参考结果,也不是一次浏览器实测。来源修订、已发布实现的选择和实际返回值是三类不同的证据。
草案要求型号调整参考理想条件下、与目标有关的基准测量。这是在指导实现如何分类,不是把页面中的整数变成基准分数。等级没有秒、每秒操作次数或利用率百分比这样的公开单位。两个等级相除不具有有效的速度比含义,因此不能把等级 4 描述为等级 2 的两倍速度。
类似地,文档的在线视频会议示例把等级对应到分辨率、效果等功能预设,但明确指出这种解释取决于应用。其他工作负载可能取决于 GPU、内存压力、网络时延或特定指令路径。根据等级选择适中的初始预设可以合理;据此保证视频流畅、模型推理性能或固定帧率,则超出了 API 值能够证明的内容。
静态等级、动态压力与计时
可复现性是一条明确的设计规则:同一设备应报告相同等级,而不是随着当前负载或利用率改变。草案还区分了修复分类错误与因新设备变快就重新定义旧等级。这既保留了等级的含义,也允许修正实现错误。“静态”不代表所有数值在任何浏览器版本和管理设置下都永远相同。
| 信号面 | 回答的问题 | 不成立的替代解释 |
|---|---|---|
navigator.cpuPerformance | 报告了哪个粗粒度静态性能类别? | 实时 CPU 负载计 |
navigator.hardwareConcurrency | 向页面报告了多少逻辑处理器? | 等级计算采用的精确操作系统输入或型号身份 |
navigator.deviceMemory | 报告了哪个近似内存类别? | CPU 分类 |
| Compute Pressure | 该 API 暴露了什么动态压力信息? | 稳定的硬件等级 |
performance.now() | 计时测量可以使用哪些时间戳? | CPU 性能类别的直接读数 |
与动态压力的区别会影响排障。标签页可能变慢,但 CPU 等级没有改变。这不自动构成矛盾,因为静态分类与变化的负载在描述不同事物。Compute Pressure 工作负载分析讨论动态反馈及其 API 边界;如果问题是如何适应变化的压力,而不是解释分类,它才是相邻的相关问题。
计时还需要另作区分。对任务计时,测量的是特定条件下的一条具体执行路径,结果包含等级并不打算持续反映的因素。性能计时隐私分析区分时间戳精度、计时观察与硬件标签。不能因为某次耗时很短,就把它填入性能等级表,仿佛两个信号使用同一个刻度。
例如,应用可能根据等级开启一个昂贵的可选视觉效果,随后出现响应不佳。首先需要问清:哪个决策使用了等级,是初始预设、持续有效的授权,还是定期重算的设置?如果只用于选择初始预设,响应差本身不能证明分类错误。负载可能需要独立的自适应机制,而且应用应该能够减少可选效果,而不必重写硬件记录。
反复读取属性同样不能代替观察真正有关的负载。草案希望等级独立于当前利用率,这意味着轮询并不应该揭示此刻 CPU 是否饱和。每秒存一次相同整数会增加活动和存储,却不能回答某个画面、计算或请求是否错过了截止时间。需要测量的问题应来自应用故障,而不是哪个 navigator 字段恰好容易读取。
隐私与最小化比较记录
WICG 隐私章节描述的是刻意压低细节的小整数披露,目标是每个等级包含大量设备和 CPU 型号,并提出每个等级覆盖至少 10% 现有型号、至少 10% 用户设备的设计意图。这些是规范目标,不是每次浏览器响应附带的人群测量。属性既没有提供分母,也没有审计证明某次部署当前达到了覆盖目标。
这会影响指纹解释。粗分类仍是可观察的类别,而且设计追求同设备可复现。报告可以把它与平台、内存及其他硬件观察放在一起。类别组合可能改变采集方掌握的信息,但小规模输出空间本身不能证明某个组合在真实人群中有多独特。仅列出可能的等级,不会得出任何唯一性百分比。
属性缺失也可能反映观察边界,而不是某个隐私功能。草案的安全 Window 暴露要求、产品实现和被检查上下文都有关。没有证据就把缺失字段归因于某个具名隐私工具,会在缺失观察之上再增加一层无依据推断。更稳妥的支持结果是保留实际采集到的具体状态,以及复现该问题所需的上下文。
| 支持记录字段 | 用途 | 采集边界 |
|---|---|---|
| 与问题有关的浏览器产品和版本 | 将结果关联到文档中的功能可用性 | 一个版本足够时,不要换成整份带识别性的请求头转储 |
| Window 上下文与安全上下文判断 | 解释采集在哪继续或停止 | 上下文被拒绝不证明缺少硬件 |
| 采集状态,以及存在时的等级 | 保留结果的实际形态 | 不把 0 或缺失改成等级 1 |
| 已知的用户或企业覆盖设置 | 解释已确认的配置差异 | 未验证时保留未知 |
| 观察日期和相关来源修订 | 区分当前案例与旧文档 | 不附带无关浏览历史或账户标识符 |
比较仍然可以有用,而不必变成一份通用指纹导出。若问题是等级意外可用或不可用,返回状态和浏览器版本可能足以确定下一步兼容性问题。原始 Canvas 输出、WebGL 渲染器字符串、已安装字体和跨站标识符并不会自动帮助回答这个问题。仅因为另一个报告也显示它们就一起采集,会扩大数据范围,却没有证明必要性。
保留期限也应服从支持任务。为解释单个功能是否可用,不需要一枚把未来访问串起来的永久身份键。浏览器升级或应用改用另一版规范时,带日期的比较可以直接记录变化。把旧等级重复当成不变的设备标签,反而会掩盖排查时应该保留的来源与配置差异。
区分声明配置和实际观察,也能避免误导性的产品对比。已知设置是配置证据,属性读取是页面可见返回状态的证据,两者不应互相替代。值与预设或参考启发式不同时,应同时保留两个事实及其来源,而不是凭空得出关于某个人硬件或意图的结论。
Chrome 支持与 BotBrowser 控制边界
Chrome 152 发布说明列出 CPU Performance API,并说明用户和管理员可以通过 Chrome 设置及企业策略覆盖报告的等级。这是针对 Chrome 实现的陈述。WICG 草案的分类算法本身,并没有为其他所有浏览器产品或嵌入应用记录同样的设置。
因此,报告值不一定总是未经改变的操作系统分类。已知的 Chrome 覆盖设置是可见结果的一项具体替代输入。如果排查无法获得这项设置,合理结论就是没有验证覆盖状态。页面不能检查管理员的策略配置,不是直接假定“没有覆盖”的理由。
版本证据也有类似边界。一项功能出现在 Chrome 152 的发布说明中,只能说明该版本所记录的功能,不证明移动应用中的嵌入浏览器采用相同配置。单独一条 Chromium 版本字符串,不能确定外围产品做出的功能选择。实际页面上下文中的功能检测应配合文档核对,不能被品牌或版本假设取代。
与 Worker 对比时尤其需要注意:固定 IDL 的暴露范围是 Window,扩展的是 Navigator,不是 WorkerNavigator。在主窗口读取数值,再发送给 Worker,只是在 Worker 中创建了由应用传入的值,并未证明 Worker 原生提供该属性。支持记录应保留原始读取发生的上下文,而不是凭一条转发消息宣称跨上下文一致。
BotBrowser CPU 核心数参考文档记录了 navigator.hardwareConcurrency、--bot-cores 选项及 Worker 亲和性限制。文档说明 Linux 和 Windows 支持亲和性;macOS 仍报告配置的数量,但没有这项亲和性机制。这些陈述针对具体信号面和执行限制,不是在说明 profile 或核心数开关会改写 navigator.cpuPerformance。
存储与内存参考文档描述的是独立的内存报告能力。内存类别不能确定 CPU 等级,存储或堆设置也不能证明对该属性的控制。对比要把某个信号面的控制归给产品设置,产品文档首先需要明确命名该信号面。之后的直接观察,也只能支持其记录环境内的较窄结果,不能升级为普遍的保护承诺。
常见问题
等级未知时应该关闭所有可选功能吗?
应用可以为 0 选择保守预设,但 WICG 示例展示的是另一种应用特定的选择。未知值并不编码一个唯一且强制的负载预设。需要分开保存观察记录和应用策略,并在实际响应差时允许调整昂贵功能。策略可以演进,不必假装原始属性提供了更精确的分类。
等级可以作为授权凭据吗?
API 返回的是一个小范围性能类别,不是经过签名的授权声明。Chrome 还记录了用户和管理员覆盖能力。服务判断某项操作是否允许,需要与判断相匹配的证据;硬件分桶并不提供这种证据。把它用作登录凭据,会赋予它属性类型和所引文档都没有定义的信任含义。
后续规范增加了等级怎么办?
保留原始正整数,让它与已知的 1 到 4 保持可区分,并明确选择应用的回退行为。草案明确预期未来可能增加更高等级,而当前 getter 算法仍断言现有范围。具备向前兼容性的调用方,不应仅因自己的显示标签还未更新,就把不认识的类别变成采集错误。
等级稳定就不需要为比较记录日期吗?
观察仍然属于某个浏览器版本、产品配置和来源修订。草案允许修正分类错误,Chrome 也记录了覆盖设置。日期和版本能够解释为什么两个记录建立在不同假设下。它们应该作为支持问题的来源信息保存,而不是被用来创建长期身份记录。
来源
- 固定版本的 WICG CPU Performance API 草案
- 固定版本的 WICG 安全与隐私问卷
- Chrome 152 CPU Performance API 发布说明
- BotBrowser CPU 核心数参考文档
- BotBrowser 存储配额与内存报告参考文档
实践结论
先记录暴露状态,再解释 navigator.cpuPerformance。正值等级可作为应用行为的粗粒度初始输入;0 要与属性缺失分开,未知的未来值也应保留,而不是替它编造含义。兼容性问题属于实际浏览器产品和 Window 上下文。一个核心数设置、一套参考启发式或低细节等级,不足以证明 CPU 身份、产品对这个独立属性的控制,也不足以证明无关服务的决策结果。
本文属于指南: 什么是浏览器指纹?原理、风险、信号与隐私边界