返回知识中心
指纹

音频指纹详解:AudioContext 如何追踪你

了解 AudioContext 和 OfflineAudioContext 的渲染差异如何形成音频指纹,以及如何让音频输出与已加载的配置文件保持一致。

BotBrowser Team

文档中心

想直接看维护中的产品文档?

这篇文章对应的主题已经有文档中心页面。需要规范流程、当前参数和长期参考时,优先看 docs。

BotBrowser 可以在声明 profile、tier、deployment mode 并固定 --bot-noise-seed 的授权测试中,让 AudioContext 读回结果具备可复现性。但它不保证匿名、被网站接受,也不保证所有宿主、配置文件或音频栈都产生完全相同的渲染。

观看视频

这段英文视频讲解静默页面如何通过离线渲染读取浏览器音频引擎的数值,并在本地浏览器检查中用同一采样率运行固定的 Web Audio 流程两次,再用更高采样率运行一次。检查不使用代理或配置文件,也不证明身份、匿名性、访问结果或远程网站的判定。音轨为英文。

为什么音频会成为指纹

每个网络浏览器都内置了音频处理系统。Web Audio API,具体来说是 AudioContext 和 OfflineAudioContext,允许页面完全通过软件创建、连接和分析音频信号。它不需要麦克风权限,不会播放任何声音,也不会弹出权限提示。这套 API 的初衷是正当用途,例如游戏、音乐应用和实时音频效果。但让这些应用运转的同一条处理管线,也可能在不同渲染条件下产生不同测量,追踪系统可以把这种差异与其他信号结合起来。这个标识符就叫音频指纹;它是否可复现取决于测量条件,清除 cookie、升级或改变上下文后并无保证。页面如何访问这套 API,以及音频在日常工作流中的用法,可参阅 Web Audio API 访问与音频工作流。

这种差异并不是某个浏览器的缺陷。Web Audio 规范描述了每个节点应该做什么,但真实机器上得到的浮点结果取决于具体实现、操作系统的音频栈和所用的采样率。两台设备可以运行完全相同的 JavaScript,却得到在低位数字上不同的缓冲区。这些数字很小,但在同一台设备上可以重复出现,正是这种组合让它成为有用的信号。

下面的各节沿着这种差异从来源一路讲到实际检查:它来自哪里,为什么常见的隐私措施会留下可见的不一致,BotBrowser 的文档对音频输出说明了什么,以及如何在你自己的配置中确认一致性。

TL;DR

  • Web Audio 和 OfflineAudioContext 可以在不需要麦克风权限、也不播放声音的情况下暴露可重复的渲染差异。
  • 音频值只能说明已声明的浏览器版本、配置文件、采样率、声道布局和上下文,不足以证明物理设备。
  • VPN 和清理 cookie 不会改变本地音频渲染;只随机化部分值还可能让报告值与实际样本不一致。
  • 在有效配置文件和文档规定的 ENT Tier2 条件下,固定 --bot-noise-seed 可以让授权的可比会话更容易复现。
  • 音频必须与 canvas、WebGL、字体和 navigator 值一起检查;BotBrowser 不能保证匿名或网站接受。

内容导航

同一段 Web Audio 例程可能因声明的渲染条件得到不同样本总和;加载配置文件并固定种子后,可在可比会话中复现。

这张图用一幅画概括了整个思路。例程保持不变,但声明的渲染条件可能改变数字;当浏览器版本、配置文件、部署和上下文保持一致时,固定种子的配置文件可以让可比会话具有可复现输出。

无声音频渲染对隐私的影响

音频指纹对追踪者很有吸引力,因为它悄无声息。用户不会收到通知,不会看到权限对话框,也没有任何视觉迹象表明正在进行音频处理。页面可以创建离线渲染上下文,处理一小段缓冲区,并在不到一秒的时间内读出结果,全程不会接触扬声器。

公开的网络测量研究(例如 Englehardt 和 Narayanan 2016 年对一百万个网站的研究)记录过一些脚本,它们把音频渲染作为识别回访浏览器的多个信号之一。这个信号很少单独使用。它会与 canvas、WebGL、字体、屏幕属性和 navigator 值组合在一起,每增加一个信号,就会进一步缩小可能产生该组合结果的设备范围。显示器刷新率与视频节奏是另一类与时序相关的信号,详见帧率指纹:刷新率与视频节奏。

当浏览器版本、配置文件、音频参数和会话条件都被声明且保持不变时,重复测量的音频结果可能保持相似。这不是无条件的持久性保证:升级、渲染参数和上下文都可能改变测量。因此,隐私窗口、清除 cookie 或使用 VPN 本身不能证明这个信号是否发生了变化。

因此,隐私问题不在于网站能否使用 AudioContext。音频是网络平台的正常组成部分,很多网站依靠它播放声音。问题在于,音频例程返回的数字是否反映了你的真实硬件,以及这些数字是否与浏览器对外报告的其他信息保持一致。

OfflineAudioContext 的渲染结果为何因设备而异

Web Audio API 提供了两个与本主题相关的主要接口。

AudioContext 负责实时音频处理。它创建一个音频图,图中的节点代表振荡、增益控制、压缩和分析等操作。每个节点处理音频采样,输出取决于底层的音频子系统。

OfflineAudioContext 把音频渲染到缓冲区,而不产生可听见的声音。它的运行速度快于实时,渲染不需要用户手势,并以浮点采样数组的形式返回结果。因此,当音频被当作设备信号时,它是最常用的接口。在概念层面,典型的例程会把振荡器连接到压缩器,渲染一小段缓冲区,再把得到的采样归约为一个数字,例如求和。

为什么输出会因设备而异?有几个因素。

  • 渲染参数和浏览器实现。 浏览器版本、内部精度、优化路径和渲染参数都可能改变产生的采样。离线渲染不会直接经过扬声器或音频硬件。
  • 协商出的配置。 采样率、声道布局和上下文可能随主机及部署模式变化。测得的差异本身不能证明具体的硬件或驱动原因。
  • 浏览器实现。 Chromium、Firefox 和 WebKit 各自独立实现 Web Audio 规范。它们的内部精度、快速路径优化和构建设置都不相同。
  • 采样率协商。 默认采样率取决于操作系统和硬件。默认 44100 Hz 的系统与默认 48000 Hz 的系统,即使节点和参数完全相同,压缩器的输出也不同。
  • 声道布局。 输出声道的数量及其混合方式,会改变例程读回的缓冲区。

结果是,渲染出的缓冲区可能包含取决于实现和声明参数的数值差异。样本总和不是分数,本身没有任何含义。离线结果不能单独证明某个具体硬件或操作系统音频栈是原因。

一个有用的思维模型是:音频结果是对整个播放栈的一次测量,并且在用户不知情的情况下完成。读取 AudioContext.sampleRate 告诉页面该栈协商了什么采样率。渲染缓冲区告诉页面该栈如何处理运算。读取分析器输出告诉页面分析节点在同样的输入上如何表现。这些读取每一项都很廉价,都不需要权限,合在一起,它们对主机的描述远比任何单个数值精确。

为什么 VPN、噪声扩展和随机化会留下不一致

有几种常见措施有时被当作音频指纹的解决方案。在依赖它们之前,值得了解各自的局限。

VPN 会改变你的 IP 地址,但对音频渲染没有任何影响。Web Audio API 完全在浏览器内部运行,没有网络环节。无论你通过 VPN、代理还是直接连接,音频结果都是一样的。

浏览器扩展提供的音频保护,通常是拦截 JavaScript 调用并给返回值加入随机噪声。这种做法有三个局限,你可以在自己的测试中检查。第一,真实设备会重复自己的结果,所以同一例程在你的测试中每次运行都返回不同的值,说明输出不稳定。第二,扩展可能只覆盖部分方法,例如缓冲区读取,而对 AnalyserNode.getFloatFrequencyData 这类相关方法保持不变,因此请把相关的值放在一起比较,确认它们相互吻合。第三,扩展工作在页面层面,并不改变音频最初是如何渲染的。

随机化音频参数,例如采样率或声道数,常常会破坏依赖准确音频播放的应用。音乐制作工具、视频通话和游戏都依赖稳定的音频行为。而且,随机化后的值还必须与实际渲染的内容一致。报告的采样率与渲染输出不匹配,是任何真实设备都不会产生的组合。

直接屏蔽 AudioContext 是最生硬的选择。它阻止了信号,但也阻止了正当的音频,而且对现代浏览器来说,缺少音频接口本身就不寻常。

让所有用户输出统一会减少信号中的信息,但会产生一个共享的值,这个值对使用它的群体而言反而是特征。在受控环境中这可能是合理的取舍,但它与让音频和某个特定设备配置文件保持一致是两回事。

共同的主线是一致性。有效的做法必须让三件事保持对齐:页面读取的值、实际渲染的采样,以及浏览器报告的其余身份信息。只改其中一项,会留下比原来的差异更难解释的不一致。

BotBrowser 的音频行为与启动选项

根据 BotBrowser 的音频文档,在有效配置文件以及文档规定的 tier 和部署条件下,BotBrowser 可以对 Web Audio 输出应用确定性噪声。每个结果仍需针对实际使用的版本、配置文件、选项和上下文验证。

由配置文件驱动的噪声,默认启用。 AudioContext 噪声默认启用。--bot-noise-audio-context 选项可以显式控制它,默认值为 true,设为 false 则关闭。

使用噪声种子实现可复现性。 --bot-noise-seed 旨在让可比会话之间的音频输出具备可复现性,并需要 ENT Tier2。重复使用同一种子也可能让会话具有关联性;它不保证所有版本、主机、部署或上下文都产生相同输出。没有固定种子时,噪声按设计在每个会话之间变化。

跨执行上下文的一致性。 文档描述了同一会话中主线程、Web Worker 和 Service Worker 之间的一致性。应针对具体版本和上下文验证这一能力,不能把它当作普遍保证。

供你自行检查的录制工具。 BotBrowser 提供 AudioLab,这是一个记录页面在会话期间所做 Web Audio API 调用的工具。文档把它说明为研究音频信号如何被收集、并验证你自己配置的一种方式。

同样存在限制。只有加载了有效的配置文件,BotBrowser 的输出才会跟随配置文件。固定种子的可复现性取决于 ENT Tier2 级别。某些 headless 配置可能根本不会初始化音频,所以在依赖结果之前,请确认你的部署模式支持音频。音频只是众多信号之一,一致的音频结果并不能保证某个具体网站会如何对待一个会话。这些限制会在本文末尾的要点中再次说明。

基本配置文件加载

最简单的配置是加载一个包含音频参数的配置文件:

chrome --bot-profile="path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

这一个选项就能让音频行为跟随已加载的配置文件。

使用噪声种子实现可复现的音频

要让不同会话得到可复现的音频结果:

chrome --bot-profile="path/to/profile.enc" \
       --bot-noise-seed=42 \
       --user-data-dir="$(mktemp -d)"

相同的配置文件和种子组合会给出相同的音频输出。更换种子会得到不同但同样稳定的结果。种子接受从 1 到最大无符号 32 位整数的整数值,取值 0 则保留配置文件默认值而不使用确定性种子。该选项需要 ENT Tier2。

Playwright 集成

const { chromium } = require('playwright');

const browser = await chromium.launch({
  executablePath: 'path/to/botbrowser/chrome',
  args: ['--bot-profile=path/to/profile.enc', '--bot-noise-seed=42'],
});

Puppeteer 通过 args 选项接受相同的参数。这些选项都是普通的浏览器参数,所以同样的配置文件和种子在这两个库中都适用。

查看配置文件的基础输出

如果你想看到不带噪声的配置文件基础音频输出:

chrome --bot-profile="path/to/profile.enc" \
       --bot-noise-audio-context=false \
       --user-data-dir="$(mktemp -d)"

这是一个对比步骤,不是推荐的默认设置。它展示配置文件在加入噪声之前本身贡献了什么。

在你自己的配置中验证音频一致性

要确认音频输出跟随已加载的配置文件,请在你自己的会话之间比较结果。使用你自己掌控的测试页面或公开的指纹测试页面,并记录每次启动时显示的音频值。

可复现性检查。 用相同的配置文件和相同的 --bot-noise-seed 启动两个独立会话,在每个会话中运行同一个音频例程,并比较输出。两个结果应当一致。再用不同的种子启动第三个会话,确认它的结果不同,但重复运行时保持稳定。固定种子需要 ENT Tier2。

跨机器检查。 在两台物理机器上运行相同的配置文件和种子,并比较输出。记录浏览器版本、部署模式、音频参数和主机条件;一致只说明这组配置的证据,不能保证所有机器都一致。

上下文检查。 在同一会话中,分别在主页面和 Web Worker 内运行同一个例程。文档说明结果在这些上下文之间保持一致,因此两者出现差异,就是需要复查配置文件和选项的信号。

关联值检查。 比较你的配置报告的采样率、离线渲染产生的缓冲区,以及分析器节点的频率数据。它们看起来都应该来自同一台设备。报告的值与渲染输出不吻合,说明你的配置需要再看一看。

调用记录。 如需更深入的检查,AudioLab 可以记录页面在会话中所做的 Web Audio 调用,让你在决定比较什么之前,先了解页面实际用到了哪些音频功能。

这些检查都在你自己的机器上运行。它们不需要麦克风权限,也不依赖你的网络,所以有用的检查都发生在浏览器内部。

解读你自己的音频结果

音频数字很容易被误读,因为它们看起来是任意的。在检查你自己配置的输出时,这三个问题会有帮助。

第一,报告的配置与渲染输出是否一致?你可以直接读取采样率和声道数,离线渲染一小段缓冲区,并把结果与该配置应当产生的结果比较。当两者来自不同的地方,例如在未修改的渲染之上改了采样率,这种组合就不是真实设备会产生的。报告值与渲染采样之间的一致,比任何单个数字都重要。

第二,音频结果是否与配置文件的其余部分一致?声称是某个操作系统的配置文件,不应返回另一个系统的音频行为。音频本身说明不了什么,所以必须把配置文件作为一个整体来考虑,同时看 canvas、WebGL、字体和 navigator 属性。

第三,结果在应当稳定的时候是否稳定?真实设备每次运行同一例程都返回相同的值。如果你自己的测试每次调用都返回不同的值,说明你的配置不可复现,需要重新检查配置文件和参数。使用 BotBrowser 时,用相同的配置文件和相同的 --bot-noise-seed 启动两个会话并比较输出,是确认你的配置可复现的最简单方法。相同配置文件下换用不同种子,应当得到不同但自身仍然一致的结果。

--bot-noise-audio-context=false 选项只有一个特定用途。它展示不带噪声的配置文件基础输出,当你想了解配置文件本身贡献了什么时很有帮助。请把它当作对比步骤而不是默认设置,因为噪声默认启用,大多数配置应当保持这样。

更换 IP 地址、清除 cookie 或打开隐私窗口不一定会改变音频测量。应检查已声明的渲染条件,而不要据此推断信号具有绝对持久性。

请保持现实的预期。一致的音频结果是连贯浏览器身份的一部分。它并不能告诉你某个具体网站会接受还是质疑一个会话,应当与其他表面一起检查,而不是孤立地看。

让音频保持一致的配置习惯

  • 始终加载配置文件。 不使用 --bot-profile 运行 BotBrowser,意味着音频输出来自你的本机硬件。让音频输出跟随声明平台的,正是配置文件。
  • 让配置文件匹配你的用例。 Windows 配置文件会产生典型的 Windows 音频输出。请选择与你正在测试的平台相匹配的配置文件。
  • 除非在做对比,否则保持音频噪声启用。 --bot-noise-audio-context=false 选项会去掉一层变化。用它做基础配置文件的对比,然后再把噪声打开。
  • 检查你的部署模式。 某些 headless 配置可能不会初始化音频。在比较结果之前,请确认你使用的模式中音频可用。
  • 覆盖其他表面。 音频只是众多信号之一。请使用同时覆盖 canvas、WebGL、字体和 navigator 属性的完整配置文件,并一起检查它们。
  • 比较期间固定版本。 如果两个会话之间浏览器版本或配置文件发生变化,音频输出的差异可能来自这个变化,而不是你的选项。

FAQ:关于音频指纹的常见问题

问:音频指纹需要麦克风权限吗? 答:不需要。它使用的是 Web Audio API 的合成与处理功能。不涉及麦克风、权限或可听见的声音,整个例程完全通过软件运行。

问:我能知道某个网站是否在使用音频处理吗? 答:原则上,你可以在浏览器开发者工具中观察 AudioContext 和 OfflineAudioContext 的创建,AudioLab 也可以记录页面在会话中所做的 Web Audio 调用。脚本经常被混淆,所以看不到明显的调用,并不能证明什么都没有发生。

问:噪声种子会影响音频播放质量吗? 答:噪声种子控制的是被用作设备信号的音频值中的细微数值变化。BotBrowser 的音频文档把它描述为作用于 Web Audio 输出的噪声,你应当在自己的部署中测试自己依赖的具体音频工作流。

问:固定噪声种子时,音频输出有多稳定? 答:根据文档,相同的配置文件和种子在不同会话之间给出相同的音频输出。请把它视为有效配置文件在 ENT Tier2 级别下的文档化行为,并用上文所述的两会话检查来确认。

问:用相同的配置文件但不同的噪声种子会怎样? 答:每个种子都会给出不同但稳定的音频结果。当不同会话需要各自不同、可重复的音频值时,这很有用。

问:为什么我的结果在 headless 和有窗口运行之间不同? 答:文档指出,某些 headless 配置可能不会初始化音频,所以两种模式的行为可能不同。请确认你的部署模式中音频可用,并在相同条件下比较。

问:VPN 或代理会改变音频结果吗? 答:不会。音频结果来自浏览器内部的渲染,所以网络路径的变化不会改变它。

问:只有音频一致就够了吗? 答:不够。音频只是众多信号之一。一致的音频结果有帮助,但 canvas、WebGL、字体和 navigator 属性也需要与之吻合。

结论与下一步

音频指纹利用不同设备通过 Web Audio API 处理音频信号时的自然差异。因为它不需要权限且不产生可见效果,它是用户较难察觉或防范的追踪方法之一。BotBrowser 在浏览器自身的音频渲染内部,对 AudioContext 和 Web Audio 输出应用由配置文件驱动的确定性噪声,该功能默认启用,因此音频结果跟随已加载的配置文件,而不是你主机的硬件。配合固定的 --bot-noise-seed(需要 ENT Tier2 级别),输出可在不同会话间复现,你可以自行验证:用相同的配置文件和种子启动两个会话,并比较音频输出。它的限制也很明确:BotBrowser 不能保证网站不会检测或拦截自动化,不能替代完整配置文件还必须覆盖的其他指纹表面(canvas、WebGL、字体、navigator),也不会改变网站所见的 Web Audio API 表面或调用行为,只有输出值跟随配置文件。音频结果仍取决于有效的配置文件、你的级别和固定的种子。你可以在功能页面查看完整的保护范围,或在验证中心自行验证音频一致性。

相关主题请参阅 什么是浏览器指纹 和 WebGL 指纹保护。Canvas 与确定性模式检查仍是独立的回归表面。

来源

本文中关于 Web Audio 和 BotBrowser 的说明所依据的公开资料:

#Audio#浏览器指纹识别#Audiocontext#隐私

本文属于指南: 什么是浏览器指纹?原理、风险、信号与隐私边界

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。