伪装 user-agent 可能反而缩小你的匿名集,并暴露与 Client Hints 的矛盾,让你更容易被识别——本文讲解熵悖论,以及伪装何时真正有用。
修改 user-agent 听起来是显而易见的隐私手段:告诉网站你用的是另一种浏览器,它就没法把真实身份钉在你头上。但现实往往适得其反。一个伪装后的 user-agent 可能比它替换掉的真实值更罕见,而且它几乎总会和浏览器透露的其他信息对不上——这两个问题都会让你更容易被单独识别出来,而不是更难。这不是说永远不该碰 user-agent,而是提醒你:在依赖伪装之前,先弄清楚它到底改变了什么。
核心要点
- 风险在于罕见,而不在于说谎本身。 一个鲜有其他访客共享的伪装 user-agent,带来的识别熵可能比它替换掉的真实值更高——背后的原理见熵与匿名集的数学关系。
- 这行字符串很少单独出现。 User-Agent Client Hints、
navigator.userAgentData以及数十种引擎层面的行为,即便字符串已经改了,仍会继续报告你真实的浏览器,由此制造出一个脚本可以标记为「说谎」的矛盾。 - 检测无需证明这是谎言——只要有一个信号与所声称的身份不一致就够了,这正是如今网站检测 user-agent 伪装的方式。
- 只有当伪装把你推向一个常见、内部一致的身份时才有帮助——而不是推向一个随机或异常的身份。
- 统一胜过随机化。 让所有用户看起来一样的工具,会缩小整个群体的总熵;而让单个用户与众不同的工具,只是把「显眼」这顶帽子换了个人戴。
修改 User-Agent 到底改变了什么
user-agent 字符串是浏览器在每次请求中发送的一行文字,用来声明自己的名称、版本和平台。一个扩展或 DevTools 设置就能随意改写这行文字——没有什么能阻止你在 Windows 桌面上用着 Chrome,却告诉服务器自己是 iPhone 上的 Safari。但它无法改写其他一切。渲染引擎、JavaScript 运行时、HTTP 请求头集合、TLS 握手,以及数十种其他可观测属性,依旧会表现得和真实浏览器一模一样,因为它们都不会去读那行被伪装的字符串来决定自己该怎么做。你只是改变了一项关于身份的声明,而剩下大得多的一堆证据仍在诚实地证明真相。
熵悖论:罕见才是问题,说谎本身不是
抵抗指纹追踪的关键不在于隐藏信息,而在于不显眼。正如熵与匿名集的详解所说,脚本能读取的每一项属性都会按其取值的稀有程度贡献相应的熵:常见值代价低,罕见值代价高,而来自独立信号的比特会累加。EFF 最初的 Panopticlick 研究测得,仅 user-agent 字符串一项就贡献了大约 10 比特的熵——这在使一份指纹在全球范围内唯一所需的约 33 比特中占了不小的比重(参见 EFF 对 Panopticlick 结果的总结)。
需要说明的是,这 10 比特是历史高点,而非今天的数字。Chrome 的 User-Agent 缩减此后把这行字符串削减成了粗粒度、且大体冻结的形式,因此如今一个诚实的 Chrome 字符串所携带的熵,远少于 2010 年的水平。这反而让伪装这笔账更不划算:你要替换掉的那个诚实字符串如今格外廉价,而任何不符合缩减后应有形态的取值,则格外昂贵。
问题恰恰出在这里。如果你伪造成一个鲜有其他访客使用的 user-agent——一个过时的浏览器版本、一个冷门的操作系统构建、一个不匹配的设备类别——你并没有摆脱这部分熵贡献,反而很可能增加了它,因为一个罕见的声称身份,按定义就是缩小了「可能是你」的那群人的范围。选择一个流行、当前、毫不起眼的浏览器字符串,是唯一不会反过来增加熵的伪装方式——但即便如此,也只有在你指纹的其余部分不会立刻与之矛盾时才成立,而这正是下一个问题。
矛盾检测:当各种说法对不上
即便挑选了一个恰当、常见的 user-agent 字符串,它也必须经受得住与浏览器暴露的所有其他信息交叉核对——而这道检验,恰恰是大多数伪装尝试真正失败的地方。
User-Agent 与 Client Hints 的矛盾
Chromium 系浏览器通过 navigator.userAgentData 暴露了 User-Agent Client Hints——这是一个结构化、可由脚本读取的来源,提供与 user-agent 字符串相同的浏览器与平台信息,但走的是一条完全独立的 API。大多数 user-agent 伪装工具只修补字符串本身就止步了,导致 navigator.userAgentData 底层仍在报告真实的 Chromium 品牌与平台,而 user-agent 字符串却声称自己是 Firefox 或 Safari——而这两款浏览器根本不会暴露 userAgentData。同时读取两者的服务器或脚本会看到:浏览器一边声称自己是某种身份,另一边一个更难伪造的独立 API 却坚持说它是另一种身份。仅这一处矛盾,往往就足以让这个会话被标记,这也是网站检测 user-agent 伪装的核心手法之一。
「说谎」标记与跨信号核查
指纹研究工具把这个思路直接形式化了。它们不会只读取一个值一次,而是通过多条路径读取同一个底层事实——一个属性对比一个衍生行为,主线程的结果对比在别处进行的同一计算——并把不一致标记为说谎。这正是 CreepJS 一类项目背后的模型,它们衡量的是浏览器的一致性,而不是唯一性(通用机制参见测谎机制如何识破伪装)。一个被打过补丁的 navigator.userAgent getter,恰恰是这类检查专为揪出而设计的目标:字符串说的是一回事,而通向同一事实的其他十几条路径说的是另一回事。
伪装何时有用,何时有害
伪装的效果完全取决于它把你推向哪个方向——是推向人群,还是推离人群。
| 场景 | 对你匿名集的影响 |
|---|---|
| 伪装成罕见或过时的浏览器字符串 | 缩小匿名集——你现在匹配到的是一个更小、更不寻常的群体 |
| 伪装成流行、当前的字符串,且与你真实的引擎行为相符 | 大致中性,前提是没有其他信号与之矛盾 |
| 只伪装字符串,却不动 Client Hints / 引擎行为 | 缩小匿名集——矛盾本身就成了一个罕见的、可识别的信号 |
| 出于测试/兼容目的使用(查看移动端布局、QA) | 没问题——你的目的不是对抗追踪,只是检查渲染效果 |
| 每次会话或每个网站都随机化字符串 | 缩小匿名集——不同访问间身份不一致,本身就是一种破绽 |
每一行的规律都相同:只有当结果既常见又内部一致时,伪装才不会增加熵。任何让你更罕见或与其他信号矛盾的做法,都会削弱它本想达成的目标。
融入人群原则
这正是为什么最有效的反指纹工具建立在统一性之上,而不是逐一随机化单个信号。Firefox 的 resistFingerprinting 模式和 Tor Browser 并不试图隐藏你的 user-agent——它们把它连同时区、屏幕尺寸和 canvas 输出一起,在整个用户群体中标准化为相同的报告值。如果使用该模式的每个人都报告一组完全相同的值,那么无论这组值与底层的「真实」配置相比如何,它所携带的熵都接近于零。相比之下,自行随机化单一信号可能会像伪装一样适得其反:一个奇怪的随机 canvas 哈希,或者每次访问都变化的 user-agent,本身就是一种可被检测的模式,这一点在Canvas 噪声 vs 真实哈希:随机化为何适得其反中有深入探讨。这个教训不止适用于 canvas:孤立地改变一个信号,却不与其他做同样事情的人保持一致,往往只是把一种可见性换成了另一种。
检查你自己的浏览器
你不必凭空相信这些结论——你可以亲眼看到这种矛盾。用扩展或 DevTools 的设备模拟伪装你的 user-agent,然后打开控制台,对比 navigator.userAgent 和 navigator.userAgentData:在 Chromium 上,无论前者现在声称什么,后者始终如实报告你真实的浏览器。BrowserInsight 的指纹检测会展示脚本可能组合利用的完整信号集,而浏览器内核检测会直接把你所声称的身份与实际的渲染引擎进行对比。若想更全面地对比伪装前后你匿名集的变化,EFF 的 Cover Your Tracks 工具会依据其自有的聚合数据集,给出「N 分之一」的估算——分别在开启和关闭伪装工具的情况下运行一次,就能看出它究竟把你推向了哪个方向。
常见问题
那我是不是永远不该改 user-agent?
不是永远不该——只是不该把它当作独立的隐私手段。出于兼容性测试或查看移动端布局而伪装是没问题的,因为你并不是想对抗追踪。但作为隐私措施,一个孤立的伪装字符串,如果没有配合 Client Hints 和引擎行为一起改动,通常会增加而不是减少可识别的熵。
这是不是说会修改 user-agent 的隐私扩展都不好?
不一定——关键在于它们是否一致地改变了整个身份。一个设计良好的工具会把 user-agent、Client Hints 及相关信号协调一致地一起改动,并致力于形成一个常见的、共享的配置。而只修补字符串、或每次访问都随机化的工具,往往会以上述方式让情况变得更糟。
指纹熵悖论是 user-agent 伪装特有的吗?
不是——它适用于任何信号。随机化 canvas 哈希、屏幕分辨率或字体列表,只要随机化后的值罕见或与其他信息不一致,就会有同样的失效模式。user-agent 只是大多数人最先想到、也最容易伪装得糟糕的信号。
如果伪装不管用,什么才能真正降低我的指纹?
标准化,而非伪装。像 Tor Browser、Firefox 的 resistFingerprinting 这类致力于让大量用户报告完全相同取值的浏览器与模式,确实能降低普通用户的平均熵,因为你所融入的那群人是真实且庞大的。完整的信号集及这些工具需要协调的内容,参见指纹识别完全指南。
结语
user-agent 字符串只是数十种信号中的一个,孤立地修改它并不会移除信息——它只是添加了一条新信息:这个声明是否与其他一切都对得上。一个罕见的伪装身份会独自缩小你的匿名集;一个不一致的身份则会给检测器递上一个现成的破绽。真正有用的「伪装」,是那些看起来根本不像伪装的版本——匹配一个庞大、常见、内部一致的配置,这正是所有真正有效的反指纹工具背后的共同原理。
推荐阅读:


