CreepJS 音频报告:渲染与缺失值
沿固定版本 CreepJS 源码区分离线渲染、缺失字段、lied、noise 与已知模式分支,不把音频检查结果当作身份。
BotBrowser Team
BotBrowser 文档提供基于配置文件的 AudioContext 输出,以及用于复现音频数值的固定 --bot-noise-seed。它不能保证匿名性或站点接受,这些控制也不会让 CreepJS 音频报告成为身份证明。在 CreepJS 中,整个结果缺失、某个字段不可用和某次比较被标记,具有不同的源码含义。
TL;DR
- 固定版本收集器创建单声道
OfflineAudioContext,长度为5000帧、采样率为44100Hz;这条路径不采集麦克风。 binsSample与copySample使用索引4500-4599;sampleSum覆盖更大且重叠的区间4500-4999。- 整份报告缺失、零值被显示为不可用,以及复制方法不受支持,是三种不同状态。
lied、数值型noise与已知模式查找记录特定实现中的检查,不证明人的身份或意图。- BotBrowser 的配置文件与种子控制另有文档;固定 CreepJS 源码不是这些控制的实测,也不是外部服务决策的证据。
目录
图示表达源码层面的决策路径,不是运行截图,也不会把分支标签变成设备判定。
固定版本收集器
修订版 10aa6724cd33a1015db1574211890518cd04f0cc 首先检查 window.OfflineAudioContext 是否存在。检查早于音频图的创建,因此此处缺少报告只说明这个收集器没有进入渲染路径,不证明主机没有音频能力。BotBrowser 文档说明了授权运行中的配置文件相关 AudioContext 输出控制;CreepJS 收集器不测量这些控制,也不承诺远端服务的结果。
构造函数存在时,代码选择 bufferLen = 5000、采样率 44100 Hz 的单声道上下文。渲染辅助函数创建频率为 10000 Hz 的三角振荡器并连接动态压缩器。压缩器分别连接分析器和上下文的输出端。创建音频图、调用 startRendering()、收到完成回调,是实现可能产生不同失败的三个阶段;只保留最终摘要会丢掉这个区别。
完成回调读取同一次渲染的多种表示。频域与时域数据来自分析器的不同方法,通道数据来自渲染后的 AudioBuffer,而 copyFromChannel 是可选的第二条读取路径。收集器分别保存 binsSample 和 copySample,不假设两次读取可以互换。CreepJS 字体表分析 解释另一种收集器,音频指纹基础 解释更广泛的信号;两者都不能代替这些分支特定的字段。
采样区间是明确且重叠的。位置 4500 到 4599 进入小型采样记录,sampleSum 则累加位置 4500 到 4999 的绝对值。小窗口不变而总和变化,与小窗口变化而总和不变,是不同观察。支持记录应写出字段与区间,不能把所有音频数字视为同一种值。保留源码修订版、字段名、区间边界及是否缺失,就能区分收集器版本变化与所选读取路径差异,而不必保存所有样本。
缺失值是分支结果
当整个 offlineAudioContext 结果不存在时,渲染器走独立的展示路径,对 sum、gain、freq、time、trap、unique、data、copy 和 values 显示 blocked 提示。结果存在时走另一条路径:多个数值字段使用真值检查,因此零也可能显示为 blocked,而零时域总和显示为 unsupported。仅凭显示提示不能区分所有零值或缺失原因。应保留底层字段状态,不把提示替换成一次成功的数值测量。
本修订版的 lied 汇总多种检查:已有的谎报元数据、意外的分析器频率、单独的假音频检查、采样读取不一致,以及真值为真的 noise 结果。noise 是数值:代码优先使用非零的缓冲区读写噪声因子,否则对渲染缓冲区前 100 个样本中的不同数值求和。另一方面,已知的三值模式可以把不匹配的 sampleSum 导向较低熵分支。一个标记可能来自多种原因,仪表板应保留分支细节后再判断原因。
比较应保留源码顺序:先区分构造函数或渲染缺失与已完成的缓冲区,再把分析器总和对应到产生它的方法;随后比较 binsSample、copySample 和 sampleSum,保留采样区间;最后保留 lied、noise 及解释各标记的分支。这样不会把缺失值叫作硬件差异,也不会把已知模式不匹配当成操纵证据。
常见问题:CreepJS 报告字段
音频指纹需要麦克风权限吗?
不需要。这条路径使用 Web Audio API 的合成与处理能力,不涉及麦克风、权限请求或可听声音,整个过程在软件中运行。
某个字段显示 blocked,是否说明整个收集器失败?
不是。HTML 渲染器区分整份报告缺失,与报告存在但个别字段为假值或不可用。解释提示需要同时保留源码字段和对应的渲染条件。
噪声种子是否影响音频播放质量?
固定收集器没有测量播放质量。BotBrowser 音频文档说明受支持的控制,应用兼容性取决于实际部署的构建与工作流程。
固定噪声种子时,音频输出有多稳定?
固定 CreepJS 源码不测试 BotBrowser 的可复现性。产品文档另行说明固定种子的行为,包括基于配置文件的音频与主机透传之间的区别。
同一配置文件使用不同噪声种子会怎样?
固定收集器没有选择种子的分支。不能从这次源码分析推断 BotBrowser 如何把种子映射到输出。
为什么有头与无头运行结果不同?
固定 CreepJS 收集器不包含有头与无头运行的对比。BotBrowser 音频文档说明可用性与配置有关;把报告缺失归因于运行模式前,需要单独检查实际部署。
VPN 或代理是否改变音频结果?
网络路由不是固定振荡器与缓冲区计算的输入。这个源码事实不说明两次浏览会话在其他方面完全相同,也不说明远端页面提供了同一份代码。
只有音频一致是否足够?
不够。音频只是多种信号之一。音频结果一致不证明 canvas、WebGL、字体或 navigator 属性也一致,更不决定站点的处理结果。
源码分支决策表
记录应区分源码观察和运行结果。第一个键是修订版,因为后续 CreepJS 可能移动检查或重命名字段而不改变 Web Audio API。第二个键是阶段:能力检查、音频图构建、完成、字段组装、比较与展示,失败含义不同。第三个键是字段:缺失的 sampleSum 与存在 sampleSum 且带 noise 标记不是同一事件。
| 阶段 | 源码观察 | 有依据的陈述 | 无依据的扩展 |
|---|---|---|---|
| 能力 | OfflineAudioContext 不存在 | 这个收集器没有返回音频报告 | 设备没有音频能力 |
| 音频图 | 振荡器、压缩器与分析器已连接 | 渲染选择了这些节点 | 所有浏览器都使用同一音频图 |
| 完成 | 完成处理器收到 AudioBuffer | 所选渲染已到达可读取缓冲区的阶段 | 输出证明了物理音频路径 |
| 字段组装 | 已计算总和与样本 | 命名数值来自缓冲区与分析器 | 摘要是硬件标识符 |
| 比较 | trap、谎报属性或已知模式不同 | 某个分支记录了意外比较 | 某个人或服务在欺骗 |
| 展示 | 呈现 blocked 提示或高亮差异 | 界面保留了不可用或不一致状态 | 界面是浏览器标准 |
每行对应一个有限的后续问题。构造函数不存在时检查功能暴露和页面上下文;构造函数存在但没有完成时检查生命周期错误与资源限制;缓冲区已到达而复制字段未定义时检查 copyFromChannel 支持;已知模式不匹配时先比较三值键,再决定是否修改配置文件。工单可以保留修订版、阶段、字段和分支而省略原始样本。这足以重现源码解释,也不会建立可重复使用的波形记录。
getChannelData 与 copyFromChannel 也有明确区别。两者都能读取通道零,但收集器独立采样两条路径,分别保留 binsSample 和 copySample。比较相同,只说明这些读取对所选渲染一致;比较不同,只说明这条路径发生差异。它不自动证明篡改,因为源码没有枚举所有可能影响读取的实现或包装层。
分析器字段有各自的限制。floatFrequencyDataSum 来自频域数组,floatTimeDomainDataSum 来自另一数组。后者在检查可选时域方法前就已分配;没有该方法时,它保持全零,零总和随后显示为 unsupported。总和相等不意味着数组相等,总和不同也不确定原因。支持记录应写出方法是否存在以及数组派生字段,不能只说“音频变了”。
压缩器的增益衰减是另一项独立输入。源码使用兼容路径读取 reduction,因为实现可能暴露数值,也可能暴露含 value 的对象。该分支解释了为什么构建已知模式键之前先归一化这个字段。浏览器后续版本可能改变属性形式,而不改变预期的压缩器操作。记录应注明观察到的属性路径和修订版,不承诺跨引擎相同。
采样窗口不能代表整条音轨。收集器对每个百值样本选择索引 4500 到 4599,对总和选择 4500 到 4999;前者包含在后者中。任一区间内的变化可能影响总和,但聚合可以隐藏各个绝对值之间相互补偿的变化。只比较总和可能漏掉局部变化,保存全部样本又可能超过支持问题所需的信息。应把区间边界与粗粒度比较结果放在一起。
音频图渲染与 hasFakeAudio() 会并发等待,但提供不同的依据。前者返回缓冲区和分析器字段,后者使用独立的 100 帧、44100 Hz 上下文和零频率振荡器检查通道数据。单独检查发生的 Promise 拒绝会被其错误处理器映射为 false,因此 false 不证明检查已成功完成。结果为真时,另一条分支设置 lied。这不是对两次相同渲染进行可重复性比较。
两张已知值查找表用途不同。收集器内的键组合压缩器衰减与两个分析器总和;键存在但允许值不含 sampleSum 时,代码设置较低熵标记并记录可疑数据提示。HTML 渲染器内的 KnownAudio 只以压缩器衰减为键,控制总和的展示方式。两张表都不声称枚举全部有效浏览器,这个文件也未记录它们完整的采样方法。“已知”表示出现在该实现的查找中,不是普遍正常;“意外”不证明恶意意图。
实际场景
整份报告显示 blocked。 先确认构造函数分支是否提前返回,或最外层错误处理器是否没有返回结果。这些都是源码中的明确路径,blocked 面板截图不会显示实际执行的是哪条。保留适用的错误记录、页面上下文与源码修订版,不为了填满仪表板添加回退数字。缺失本身应作为观察保留。
报告有数值,但 lied 为 true。 阅读分支消息。如果它提到分析器数值种类数量,比较分析器方法及预期的静音假设;如果它提到属性谎报,检查确切属性与执行域;如果它提到假音频,将其保留为收集器标签而不是对页面的定性;如果它提到样本比较,检查窗口定义与复制方法。后续动作取决于消息。
报告的 noise 非零。 保持数值类型与 lied 布尔值的区别。noise 为真值时,代码会设置 lied,但返回的两个字段不是别名。只保留摘要会丢掉标记来源。最小化隐私数据的记录可以保存粗粒度的“零/非零”噪声状态、源码修订版和相关字段名而不保存原始数组;应把该状态标为派生记录,而不是原始数值字段。
浏览器更新后出现已知模式不匹配。 先比较浏览器构建与 CreepJS 修订版,再比较三值模式和样本总和。源码查找表变化可能使同一浏览器得到不同分类;只改变浏览器时,结果是实现比较。两种情况都不证明新版隐私更差,也不证明旧版真实。
通道数据存在,复制字段却不可用。 解释不匹配之前检查 copyFromChannel 的支持条件。收集器通过不同 API 读取通道零,但方法不受支持时,返回的 copySample 变为 [undefined]。这不同于两条受支持读取路径产生不同样本。设置 lied 的不匹配分支也检查支持状态。把两者都归为“复制失败”会删掉解释标记所需的条件。
支持团队需要截图。 截图可以展示呈现分支,不能证明隐藏的源码字段或分支原因。将其与修订版、字段名和小型决策记录配对。避免暴露账户标识、完整原始数值或无关页面。报告用于分流兼容性问题,不用于建立可重复使用的指纹。
产品团队需要单个通过/失败指标。 先定义决策,再从分支记录派生指标。不依赖离线音频的功能可以接受构造函数缺失,音频编辑器则可能因此无法发布。lied 可以触发调查,而不必直接让用户失败。CreepJS 报告不决定产品政策,只提供供负责人解释的观察。
可复现性记录
源码分析可复现,意味着另一位读者能取得相同修订版、检查相同行范围并得到相同分支表。运行复现还需要固定浏览器构建、操作系统、配置文件生命周期、页面来源、权限与测试页面集合。缺少这些输入的记录不能区分浏览器变化与上下文变化。这里的依据仅是源码,没有声称运行输出。
获得运行记录授权时,只采集回答问题所需的最少字段。可用的 JSON 字段包括 sourceRevision、fixture、browserBuild、os、context、testedOn、phase、field、branch 与 interpretation。解释要限定范围:“copySample 与 binsSample 不同”比“音频是假的”更有依据,因为前者是观察,后者是未证实的原因。只有数据负责人批准保留时,才在受限调查中保存原始数值。
OfflineAudioContext、sampleSum、copyFromChannel、lied 与 noise 是源码中的不同键。诊断记录应保留这些名字,不合并成一个“音频状态”。对于 BotBrowser 配置,噪声种子可复现性说明 区分配置文件、构建与种子输入。还应记录 --bot-audio 使用 profile 还是 real:文档说明主机透传不应用配置文件音频数值或音频噪声。不知道启动配置时,固定种子与未变的报告不能证明使用了同一控制路径。
来源
- CreepJS
src/audio/index.ts,修订版10aa6724 - MDN:OfflineAudioContext
- MDN:OfflineAudioContext.startRendering
- MDN:AudioBuffer.getChannelData
- BotBrowser 音频文档
实践结论
使用固定源码区分收集器停在哪个阶段、读取了哪些字段。分别保留不可用输出、分析器数值、采样区间、lied 与 noise。这种分支诊断补充了 BotBrowser 音频文档 的整体说明,不提供运行结果,也不确定身份、匿名性或外部服务决策。音频仍是单一信号面的报告;CreepJS 预测聚合分析描述了另一条展示路径,并说明 unknown 与 pending 状态的边界。其他表面分别参照 CreepJS 字体表分析 与 WebGL 指纹,并保留各自证据边界。
本文属于指南: 什么是浏览器指纹?原理、风险、信号与隐私边界