
最近我在折腾一个挺有意思的项目camofox-browser。一句话说明白这是基于 Firefox 做的一个迷彩浏览器camouflage迷彩加 fox火狐给浏览器穿上一层伪装让它在成千上万种浏览器特征里变得毫不起眼。它不是什么颠覆性创新而是把 Firefox 自带的反指纹机制、企业策略配置、扩展能力组合起来工程化地解决一个问题你在网上留下的指纹太独特一抓一个准。这个问题有多严重呢你每天打开网页看起来是免费的但背后的广告平台、统计脚本、风控系统没有一个是瞎的。它们不靠 cookie 也能认出你靠的是浏览器指纹屏幕分辨率、操作系统、语言、时区、字体列表、Canvas 渲染哈希、WebGL 参数、CPU 核心数……几十项信息组合起来形成一个几乎只属于你的数字身份证。cookie 能清指纹清不掉除非你让指纹变得大众化。camofox-browser 做的就是这件事。什么人适合折腾这个两类。一类是做反指纹、隐私对抗研究的开发者可以把这套流程当作一个实验平台直观看到每个配置项对指纹的实际影响另一类是普通用户日常对隐私敏感不想被广告平台精准画像装好就能当默认浏览器用。它不需要你有很强的编程背景会复制粘贴、会看点配置文件就能跟上。下面我把整个项目的设计思路、核心配置、实操流程和踩过的坑一次讲清楚。1. 项目整体设计与方案选型为什么基座必须是 Firefox1.1 指纹追踪到底是怎么咬人的先聊最基础的。浏览器指纹不同于传统 cookie它不需要在用户机器上写任何东西完全是浏览器在访问网页时主动交代的。你打开一个网页服务器会收到一个 HTTP 请求这个请求头里就带着 User-Agent、Accept-Language、Accept-Encoding 这些信息紧接着网页里的 JavaScript 会继续从 navigator、screen、Canvas、WebGL 这些接口里读取更多细节。整个过程可能只需要几十毫秒用户完全无感。这些信息单看都不敏感但组合起来威力很大。业内有个概念叫信息熵你可以理解为不确定性的量度。单个字段比如屏幕分辨率全世界可能有几百万人都一样熵很低但把分辨率、操作系统、UA、字体列表、Canvas 哈希堆在一起联合熵就非常高了。有研究测算过普通浏览器的指纹熵值大约在 10 到 20 比特之间这意味着在几万甚至几十万浏览器里就能把你单独挑出来。类比一下身高、发型、口音、走路姿势单个特征都不算什么但你在人群中碰见一个又高又壮、留着寸头、说话带明显方言、走路还带风的人基本一眼就能锁定。这也是指纹追踪防不胜防的根本原因。清除 cookie、开无痕模式都没用指纹是浏览器出厂自带的体味藏不住只能改。1.2 为什么不用 Chromium而选 Gecko 系打底做这样一个项目摆在面前的第一道选择题就是基座选谁。市面上绝大多数浏览器都是 Chromium 套壳生态繁荣扩展丰富开发者投入也大。那 camofox 为什么偏偏选 Firefox第一Firefox 是真正开源的浏览器而且没有商业广告公司的数据变现压力隐私保护是刻在基因里的。它内置了一套 Chromium 没有的完整反指纹机制叫 Resist FingerprintingRFP可以通过一个开关把时区锁成 UTC、给 Canvas 渲染注入噪声、对硬件信息做模糊化处理。这是底层能力Chromium 系里你找不到同等完备度的官方实现都是靠第三方扩展东拼西补。第二定制方式的灵活度和维护成本天差地别。Chromium 系要改默认行为通常得改源码重新编译或者依赖开发者模式加载一堆补丁而 Firefox 提供了企业策略体系也就是 distribution 目录加 policies.json不需要碰一行源代码就能锁定偏好设置、预装扩展、设置主页、隐藏按钮完完整整定制出一个新浏览器。对于个人项目来说这个门槛低太多了。第三从指纹伪装的角度看Gecko 本身就是少数派。全球浏览器市场份额被 Chromium 系占据大半你用 Gecko 渲染引擎UA 一亮出来就跟大部队不一样。这个不一样既是劣势也是优势如果所有人都挤在 Chromium 的阵营里伪装反而困难而 Gecko 自成一体加上合理配置能在指纹空间里稳居一个相对平常的位置。选型这件事我踩过最大的坑就是想太多。刚开始我也考虑过基于 Chromium 搞一套结果发现光是把反指纹扩展的配置拉齐就得折腾很久而且很多 Chromium 的隐私配置是藏在启动参数里的管理混乱。最终老老实实回到 Firefox三小时出原型。这也算是个经验做这种定制项目选一个官方已经替你想好了隐私策略、你只需要做配置组合的平台永远比从零造轮子强。1.3 核心思路伪装优于隐身以及它覆盖的应用场景这个项目最核心的设计理念可以浓缩成一句话伪装优于隐身。互联网隐私保护其实有三条路线。第一条是封闭把脚本禁了、第三方 cookie 全杀了、存储全锁死代价是网站功能大量瘫痪很多页面直接白屏第二条是把特征抹平到极端让所有指纹都收敛到一个值理论上非常安全但代价是你成了全场唯一的异类风控系统一眼就知道你在用非常规工具反而更容易被重点关注第三条就是伪装有意识地模拟一个大众化的典型环境让指纹落在人群分布最密集的区域。camofox 走的是第三条路。它的目标不是让追踪者完全查不到你而是让追踪者查到的是一堆你分不清哪个是真的你。这个思路在实践中非常实用你不损失网页功能不需要把 WebGL 全禁掉也不用过那种人人一模一样的极端日子只需要让自己看起来像一个普通的 Windows 用户、用着一台普通的电脑、挂着普通的语言和时区就足以把你从人群里抹掉。从应用场景和影响范围来看这个项目最典型的场景有三个一是面向隐私敏感人群的日常浏览器开启后广告推荐明显变模糊跨站追踪显著减少二是作为反指纹研究人员的测试平台每个开关都能用指纹测试站实时验证效果三是企业内部做合规浏览器的原型参考通过 policies.json 统一管理员工浏览器配置。后两个场景其实是我做这个项目过程中意外发现的因为 distribution 这套企业策略写好了稍微改改就能复用。2. 核心细节解析伪装一个指纹要动哪些维度2.1 指纹画像的七个关键维度要让伪装有效先得知道追踪方在采集什么。我梳理了一下常见的指纹采集维度大致分成七类我先列出来后面再逐个讲清楚怎么防。HTTP 头信息User-Agent 和 Accept-Language 是最基础的信息。UA 直接暴露操作系统、浏览器内核和版本Accept-Language 暴露语言偏好这两项最容易被忽略而且很多反指纹方案自己也会在这一步翻车。屏幕与显示参数screen.width、screen.height、window.outerWidth 这些值能推断出设备类型配合 devicePixelRatio 还能判断你是不是开了缩放。桌面端和移动端的差异在这个维度上特别明显。Canvas 和 WebGL 渲染指纹浏览器渲染同一段图形、执行同一段 WebGL 指令时由于 GPU 驱动、渲染管线、字体渲染的细微差异最终像素数据会不同对这个像素数据做哈希就能得到高度一致的渲染指纹。这是目前准确率最高、被用得最多的指纹手段。字体枚举JavaScript 可以通过测量一段文字在浏览器中的渲染宽度差探测系统里装了哪些字体。字体列表跟操作系统版本、语言环境强相关信息量很大而且普通用户完全无感。硬件与并发信息navigator.hardwareConcurrencyCPU 核心数、navigator.deviceMemory设备内存、navigator.platform 这些接口能推测设备档次。虚拟机和实体机的差异在这个维度上比较明显。时区与本地化信息Date 对象可以返回时区偏移量Intl.DateTimeFormat 可以返回 IANA 时区名称比如 Asia/Shanghai 这种。这个字段特征非常强几乎等于直接告诉对方你人在哪个时区。WebRTC 本地 IP 泄露默认情况下浏览器为了支持在线会议、P2P 传输会通过 STUN 机制探测本地网卡和公网 IP这个信息可以被网页通过 WebRTC API 偷偷读取。很多反指纹方案漏掉了这一项一测一个准。除了这七类还有一类是行为指纹比如鼠标轨迹、按键节奏、滚动速度。这类指纹很难伪装但采集成本也高大部分广告平台不会用主要是风控系统在金融场景使用。camofox 对这个维度能做的不多但整体指纹已经大众化之后行为特征单独拿出来也构不成精准锁定的依据属于成本收益不对等不用过度担心。2.2 about:config 调优每一行配置的理由知道了对手采集什么下一步就是逐个维度布置防线。Firefox 的 about:config 是这次定制的主战场。我把 camofox 的核心配置项列出来每一项都会告诉你为什么这么设以及不这么设会有什么后果。pref(privacy.resistFingerprinting, true);这是整个项目的灵魂配置。开启后Firefox 会把时区强制为 UTC把屏幕分辨率上报值模糊化处理对 Canvas 渲染加入逐会话变化的噪声同时禁用或改写一大票高熵接口。代价是某些依赖时区的本地化功能会判断失误但在 camofox 的场景里UTC 时区本身就是一种大众化特征比直接暴露真实时区安全得多。pref(privacy.fingerprintingProtection, true);这是新版 Firefox 把指纹防护拆出来的独立开关跟 RFP 互补。RFP 侧重改写和模糊化这个开关侧重拦截已知的指纹脚本和跟踪请求两个一起开效果叠加。注意这个开关在部分旧版本里不存在如果 about:config 里搜不到说明版本不够新升级一下就好。pref(privacy.trackingprotection.enabled, true);打开内置跟踪保护。它背后是一份常见的跟踪器拦截列表能在请求层面把第三方追踪脚本直接挡掉。配合 RFP属于一个负责抹平指纹、一个负责挡掉已知追踪请求的组合。pref(media.peerconnection.enabled, false);关掉 WebRTC这一步是堵住本地 IP 泄露。我见过很多人 RFP 开了、Canvas 也防了结果指纹测试报告里赫然出现一条内网 IP 字段就是因为这条漏了。WebRTC 默认开启是为了视频会议等场景日常只浏览网页根本用不到关了不影响任何正常上网体验。pref(webgl.disabled, false);这里故意不关 WebGL甚至要确保它开着。很多新手一上来就把 WebGL 禁了以为能防渲染指纹实际上恰恰相反——禁用 WebGL 本身就是一个极其显眼的异常特征真实用户里禁用 WebGL 的少之又少。camofox 的思路是保留 WebGL让 RFP 在渲染时注入噪声这样指纹每次会话都会变化而且不会暴露我禁用了一大堆东西这个特征。pref(dom.webnotifications.enabled, false); pref(geo.enabled, false);这两个属于顺手清场。网页通知权限和地理定位权限如果不关在线服务可以在你点击允许后获取更多个人信息。关掉之后绝大多数网页功能不受影响需要用到定位或通知的时候再手动开启就行。pref(network.http.referer.trimmingPolicy, 2); pref(network.http.referer.XOriginTrimmingPolicy, 2);这两条是控制 Referer 头携带信息的。trimmingPolicy 设为 2 表示跨站请求时只发送来源域不发送完整 URLXOriginTrimmingPolicy 是专门针对跨站请求的二次裁剪。这样网站只能知道你从哪个站点来的却拿不到你访问的完整路径。信息泄露的每一种途径都得堵上这是做隐私项目的基本素养。2.3 扩展层的补充哪几个值得内置about:config 把底层开关都布置好之后还需要几个扩展在外围补漏。我经过反复测试最终只留了三个原则是能用配置解决的绝不用扩展能用一个扩展解决的绝不用两个。第一个是 uBlock Origin。这个不是拿来挡广告的而是当第一道追踪器拦截器用。它的动态过滤能力比 Firefox 内置跟踪保护更精细可以按站点级别控制脚本和第三方请求的加载跟内置保护叠加后覆盖绝大多数追踪场景。第二个是 CanvasBlocker。虽然 RFP 已经对 Canvas 做了噪声处理但这个扩展能按站点精细控制噪声强度。比如在银行、支付这类风控严格的站点用最弱策略避免被误判在普通内容站点用最强策略最大化伪装效果。它的策略引擎比单纯开 RFP 更灵活适合进阶玩法。第三个是 Temporary Containers临时容器隔离。每次打开一个站点浏览器会为它分配一个临时容器cookie 和本地存储只在这个容器内有效关掉标签页就销毁。这样即使某个站点给你种下了跟踪 cookie它也无法在下一个标签页里继续追踪你。这比单纯禁用第三方 cookie 更优雅你保留了登录状态却斩断了跨站关联。这里有一个特别重要的提醒扩展列表本身也是一种指纹。网页可以通过检测某些扩展暴露的全局对象来判断你装了哪些扩展装的扩展越冷门这个指纹熵就越高。所以 camofox 的策略是只保留这几个主流扩展它们被检测到也无妨因为全世界用这些扩展的人太多了反而成了大众化的一部分。这一点很多人在做同类项目时完全没意识到装了一堆小众扩展结果每次访问页面都等于在喊我装了这些扩展快来识别我。3. 实操过程与核心环节实现从零搭一个 camofox3.1 准备工作选 ESR 还是 Release 作为基底动手之前先要确定基底版本。Firefox 有两个大分支Release正式版每四周更新一次功能迭代快但指纹特征也跟着频繁变动ESR扩展支持版一年左右才更新一个主版本只打安全补丁特征极其固定。做指纹伪装项目我强烈建议用 ESR 作为基底。理由很简单指纹伪装的天敌就是特征漂移。你辛辛苦苦把 UA、渲染行为、字体列表都调成了一套自洽组合结果浏览器一升级Canvas 渲染管线变了字体加载逻辑变了整个指纹又得重新校准。ESR 一年才动一次大版本意味着你的伪装配置可以管用一整年不用反复校准。如果你只是自己用、不在乎维护成本用 Release 也无妨但做 camofox 这种偏工程化的项目可维护性永远排第一位。下载好对应平台的 ESR 安装包后不要急着安装先解压到一个工作目录。Windows 可以用静默安装后复制整个安装目录Linux 直接用 tar 包解压即可。后面所有定制都在这个目录里完成。3.2 三板斧定制user.js、policies.json 与扩展预装Firefox 的定制有三板斧分工不同最好配合使用。第一板斧是 user.js。它放在用户配置目录profile 目录里Firefox 每次启动都会读取它并把里面的配置项写入 prefs.js相当于每次启动时强制应用一套配置。这个文件适合放那些不想被手动改回去的项。我把前面 2.2 节里所有配置统一写进一个 user.js放在 profile 目录下效果立竿见影。第二板斧是 distribution 目录里的 policies.json。这是 Firefox 官方支持的企业策略入口可以在不修改源码的情况下锁定配置、安装扩展、定制界面。它的优先级比 user.js 更高而且配置项可以设置 Status 为 locked让 about:config 里对应的项直接变灰用户手动也改不动。这样一来camofox 的隐私基线就有了底线不怕使用者无意中把保护关掉。我给出一个可以直接用的 policies.json 示例{ policies: { DisableAppUpdate: true, DontCheckDefaultBrowser: true, Preferences: { privacy.resistFingerprinting: { Value: true, Status: locked }, privacy.fingerprintingProtection: { Value: true, Status: locked }, media.peerconnection.enabled: { Value: false, Status: locked } }, ExtensionSettings: { uBlock0raymondhill.net: { installation_mode: force_installed, install_url: https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi }, CanvasBlockerkkapsner.de: { installation_mode: force_installed, install_url: https://addons.mozilla.org/firefox/downloads/latest/canvasblocker/latest.xpi } } } }这段配置干了三件事禁用自动更新避免版本漂移导致指纹变化、锁定三个核心隐私项用户无法关闭、强制安装两个扩展并锁定安装状态。注意 install_url 用的是 addons.mozilla.org 的官方下载地址安装时会自动从官方源拉取不需要任何手工操作。这是 Firefox 企业策略的标准用法安全合规。第三板斧是让这些文件各就各位。user.js 要放进 profile 目录policies.json 的位置则取决于操作系统Windows 放在安装目录下的 distribution 文件夹里macOS 放在 Firefox.app/Contents/Resources/distribution 里Linux 放在系统 Firefox 安装目录的 distribution 里。如果文件夹不存在自己新建一个就行。整个构建目录结构大致是这样camofox-browser/ ├── firefox-esr/ # 解压后的 Firefox ESR 主程序 │ └── distribution/ │ └── policies.json └── profile/ └── user.js实际使用时把 profile 通过命令行参数指定给 Firefox 即可。Windows 上是 firefox.exe -profile 路径Linux/macOS 上是 firefox --profile 路径。这一步不用改任何官方代码浏览器就完整穿上了 camofox 的迷彩。3.3 验证环节用指纹测试站检查伪装效果配置全部到位之后最重要的一个环节是验证。不要相信我配好了这种感觉要用指纹测试站实测数据说话。我通常的做法是开两个浏览器窗口一个未配置的干净 Firefox一个 camofox分别访问同一个指纹检测页面然后把两者的报告字段逐项对比。重点看六个方面UA 是否还是 Firefox 形态注意 camofox 不刻意伪装成 Chrome而是让 Firefox 自身的指纹变得平常时区是否被改写为 UTCCanvas 哈希是否在两次刷新之间发生变化WebRTC 是否还能探测到本地 IP语言列表是否与真实系统脱钩屏幕分辨率上报值是否被模糊化。这里有一个很多人都会犯的错误改动配置后没有完全退出浏览器就重新打开检测导致部分配置没有生效。Firefox 的 about:config 大多数项是实时生效的但 RFP 相关的不少项需要重启浏览器进程才彻底生效。我建议每改一次配置就完全退出浏览器包括托盘图标里的后台进程再重新打开做测试避免拿到假数据。如果发现某一项没有达到预期按下面的顺序排查先在 about:config 里确认该项的当前值确实是你设置的再确认有没有扩展在旁边覆盖了行为CanvasBlocker 的策略优先级有时会高于 RFP最后确认版本新版 Firefox 的部分隐私特性已经迁移到 privacy.fingerprintingProtection 了旧配置可能在老版本上不生效。这几步基本能解决九成验证失败的问题。4. 常见问题与排查技巧实录4.1 伪装过度验证码无限循环与人机验证地狱camofox 踩过的最大一个坑是伪装过度导致的风控误判。具体表现是访问一些风控严格的站点时验证码永远刷不出来或者刷出来永远验证不通过有的直接弹出访问环境异常。排查下来原因主要集中在两个点。一个是 CanvasBlocker 的噪声策略太强风控系统在本地脚本里做了 Canvas 像素合法性校验你注入的噪声让它判定当前浏览器是自动化工具。解决办法是把银行、政务、支付这类关键站点加入 CanvasBlocker 的白名单或者弱化策略只在这些域名上用最轻度的伪装。另一个是时区锁定为 UTC 后某些依赖本地时区判断的风控规则会把 UTC 时区视为异常毕竟一个真实用户常年在 UTC 时区活动确实比较少见。解决办法就是接受这个现实camofox 的目标不是过所有站点的风控而是切断跨站追踪。关键服务可以单独用一个不开启 UTC 锁定的普通浏览器访问或者临时把 RFP 关掉。记住一个原则隐私工具的使用场景是防追踪不是对抗风控。如果某天你发现配置已经影响正常生活那不是配置不够强而是用错了场景。4.2 字体列表暴露真实环境字体枚举是我自己测试时最容易翻车的一项。系统装了什么字体JavaScript 通过测量文字占位宽度就能探测出来。你系统里如果装了思源宋体、霞鹜文楷这种小众字体指纹的独特性瞬间拉满。camofox 的默认配置会通过 RFP 对一部分字体探测做过拦截但实测下来对直接暴露系统字体的场景拦截得并不彻底。更可靠的做法是配合字体白名单机制在 about:config 里设置 font.system.whitelist 相关项把网页可以感知的字体数量降到一组大众组合Arial、Helvetica、Times New Roman、宋体、微软雅黑这种最常见的系统字体。中文环境下字体列表本来就很长一定要主动裁剪否则你装的每一个字体都在给追踪器递情报。另外别忽略一个细节不同系统自带的字体列表差异极大macOS 和 Windows 的默认字体名单完全不同。如果你要伪装的大众形象是 Windows 用户那么字体列表、字体渲染模式都得尽量向 Windows 靠拢。在指纹测试站上字体列表这一项是暴露操作系统的重灾区务必多测几次。4.3 性能损耗与日常维护策略开了一堆隐私配置后性能损耗是绕不开的话题。实测下来RFP 开启后 Canvas 类页面的渲染速度会有轻微下降因为多了一层噪声处理Temporary Containers 会在打开新标签页时多创建几个进程内存占用上升一点。但整体影响非常有限日常浏览几乎感觉不出差异只有在跑大型 WebGL 应用时能明显觉察。对绝大多数用户来说这个成本完全值得。日常维护方面最需要盯的是更新节奏。我前面建议用 ESR 版本并禁用自动更新但这不是让你永远不升级。安全补丁一定要打只是打之前建议在测试环境里重新跑一遍指纹检测确认大版本更新没有带来新的特征。另外user.js 每次启动都会重新写入 prefs.js如果你在 about:config 里手动改动了某个值下次启动会被 user.js 覆盖回去。这既是优点也是烦恼需要改配置时请直接编辑 user.js不要在界面上改。最后分享一个小技巧把 camofox 的配置放到 Git 仓库里管理。user.js、policies.json 都是纯文本版本管理非常方便。每次调优改了什么commit 信息里写清楚几个月后回头看看自己的变更历史能少踩很多重复的坑。我自己实际用了两三个月之后最大的感受是这个项目从根本上改变了我的隐私观。过去我以为隐私保护就是做得越狠越好现在才明白最好的隐私保护是让自己淹没在人群里——配置上克制一点、适度一点反而比极端设置安全得多。这种少即是多的思路可能才是反指纹对抗真正的进阶之路。