camofox-browser 是我维护了半年多的一个 Firefox 定制项目,核心目标很简单:把浏览器运行时暴露的“身份特征”收敛到最低,让网站、广告平台和统计脚本难以通过浏览器指纹持续勾画我的画像。
这个项目本身不算复杂,没有从零写浏览器内核,而是基于 Firefox 做了一套深度配置方案。名字里的 Camo 取“迷彩”的意思,Fox 指 Firefox,整体思路就是给浏览器穿上一件“迷彩服”,让它在外网环境里报出一组不容易被关联的身份信息。这篇博文我会把项目从动机、技术选型、反指纹原理,到具体的 user.js 配置、扩展搭配和问题排查,完整过一遍。想解决隐私追踪问题的普通用户、做前端或数据分析的技术人员,以及单纯想折腾 Firefox 的人都适合往下看。
1. camofox-browser 的项目定位与核心思路
1.1 为什么需要一款“迷彩”浏览器
先说一个容易被忽略的事实:清除 Cookie、开无痕模式,其实只解决了很小一部分追踪问题。无痕模式清得掉 Cookie,却清不掉浏览器指纹。广告平台只要拿到你的 Canvas 渲染结果、WebGL 参数、字体列表、时区这些信息,换个 Cookie 照样能把你认出来。
我当初做 camofox-browser,起因是一次很直观的体验。我开了浏览器的“严格跟踪保护”,然后去一个测试站点看自己的指纹信息,页面居然还能精确读出我的显卡渲染器、系统安装的字体、显示器的分辨率、甚至我在哪个时区。那一刻我意识到,所谓的“隐私浏览”在指纹追踪面前,基本等于裸奔。
项目定位也随之清晰了:不做“完全匿名”,只做“降低可关联性”。目标是让不同站点之间拿到的浏览器特征尽量不一致、不稳定,或者统一成一套不容易区分用户的通用值。也就是说,广告平台看到你的时候,会觉得你和其他几千几万个人长得一模一样,没办法用设备特征来长期锚定你。这个定位务实,也适合日常使用。
1.2 技术选型:为什么要基于 Firefox
这个项目不是从零写浏览器,而是基于 Firefox 做深度定制。选 Firefox 而不是 Chromium 系,我是认真对比过的,原因主要有四点。
其一,Firefox 是开源项目,核心代码公开可审阅,隐私保护相关的改动你可以一条条追踪,不存在“我替你做了某个你不知道的数据收集”这种黑箱。其二,Firefox 内置了privacy.resistFingerprinting这类系统级反指纹开关,一套机制覆盖 Canvas、WebGL、音频、时区、语言等多个维度,Chromium 生态里类似的功能大多靠扩展拼接,力度和一致性都不够理想。其三,Firefox 所有偏好可以集中写进 user.js 文件,随 profile 目录一起管理,换机器、还原配置都非常方便,非常适合“配置文件即项目”的维护方式。其四,桌面端和 Android 端共用同一套偏好体系,后续想移植到手机上也容易。
Chromium 生态的优势是兼容性更好,很多老旧的业务系统只对 Chromium 做了完整适配。但在隐私定制的自由度上,Firefox 的 about:config 暴露的内部偏好项要丰富得多,我可以精确控制每一个信息通道。就“做一款以隐私为第一优先级的个人浏览器”这个诉求来说,Firefox 是更顺手的底子。
2. 反指纹机制拆解:浏览器到底暴露了什么
2.1 常见的几类浏览器指纹
要理解 camofox-browser 改了哪些东西,得先知道浏览器在背后暴露了多少信息。简单分一下类。
第一类是设备硬件信息。网站可以通过 JavaScript 读取屏幕分辨率、颜色深度、设备的硬件并发数(hardwareConcurrency)、设备内存(deviceMemory)等。这些参数在不同电脑上差异明显,组合起来就是一组不错的标识。第二类是图形渲染指纹。网页把一段固定的图形绘制到 Canvas 上,再读回像素数据,不同显卡、不同驱动、不同操作系统的渲染结果会有细微差别,这个差值就是 Canvas 指纹。WebGL 指纹更进一步,可以拿到渲染器名称、显卡厂商,甚至 GPU 驱动版本。第三类是音频指纹。通过 AudioContext 处理一段标准音频,不同设备的声卡和底层音频栈会产生微小波形差异,这个差异同样能被提取出来当标识。第四类是字体信息。页面用一段文字和一堆不存在的字体名去做测量,通过渲染宽高的变化枚举出系统里实际安装了哪些字体,这个列表非常个人化。第五类是环境信息,包括时区、语言优先级、User-Agent、Accept-Language 头等。最后还有存储与行为特征,比如 localStorage、IndexedDB、Service Worker 的存在与否,以及页面上的鼠标轨迹、滚动行为等。
其中图形渲染指纹和音频指纹是最难处理的一类,因为它们来自设备底层能力,不是你设置一个开关就能关掉的。很多人以为“清掉 Cookie + 开无痕”就安全了,实际上你的显卡渲染同一张画布,输出结果就是和别人不一样,这串输出就是你的数字胎记。
2.2 camofox-browser 的应对思路
针对这些暴露面,我的配置思路不是“把所有接口都关掉”,因为那样会制造一个特征过于明显的浏览器,反而更容易被识别。更合理的思路可以概括成六个字:统一、模糊、隔离。
统一,就是把设备信息的取值归一化。例如把时区固定到一个默认值,把语言优先级固定成少数几项,让所有网站看到的都是同一套“标准答案”。模糊,是开启 resistFingerprinting 和相关保护后,Canvas、WebGL、音频接口返回的结果会被加入轻微噪音。这样同一个设备每次拿到的指纹都不是精确值,网站拿去做长期关联就不可靠了。隔离,是把不同用途的站点放进不同容器,Cookie、登录态、存储彼此隔离,站点之间很难通过头信息和存储相互关联。
这套组合比单独开无痕模式要激进得多。无痕模式是“我走后不留痕”,而 camofox-browser 是“我在的时候,看到的我也是假的”。两者的差别,是隐私保护思路上的根本差异。
3. 实战配置:手把手搭一套 camofox-browser
3.1 准备独立的浏览器配置环境
我的建议是不要拿你日常使用的 Firefox 直接改,而是单独建一个 profile。原因很简单:反指纹配置会影响很多网站的正常使用,把它和日常浏览混在一起,哪天需要开发调试时,你会被各种异常逼疯。
创建独立 profile 的方法是先关闭所有 Firefox 进程,然后在终端执行:
firefox -CreateProfile camofox firefox -P camofox --no-remote之后启动时都用-P camofox指定这个 profile。Linux 环境下,我习惯把 profile 目录用 Git 管理,user.js和扩展列表同步到私有仓库,换机器后十分钟就能还原整套环境。Windows 上也可以把profile路径放到一个固定位置,配合符号链接来管理,思路是一样的。
注意:
user.js文件放进 profile 根目录后,每次 Firefox 启动都会读取它并覆盖 about:config 里对应的配置项。如果你在 about:config 里手动改过某个值,下次启动又会被 user.js 拉回去,所以修改配置时尽量集中在 user.js 这一处维护。
3.2 核心参数清单与释义
Firefox 的 user.js 是配置的入口,每一行就是一个偏好项。我当前维护的配置核心如下,不一定都要照抄,刚开始可以先开最要紧的几个。
// 开启严格反指纹模式 user_pref("privacy.resistFingerprinting", true); // 给窗口加 mailto:9000 信箱化处理,避免用窗口尺寸推断屏幕大小 user_pref("privacy.resistFingerprinting.letterboxing", true); // 禁用 WebGL,把 WebGL 指纹这个大头关掉 user_pref("webgl.disabled", true); // 禁用 DRM 相关组件,减少可枚举的插件信息 user_pref("media.eme.enabled", false); // 关闭健康报告与遥测 user_pref("toolkit.telemetry.enabled", false); user_pref("toolkit.telemetry.unified", false); user_pref("datareporting.policy.dataSubmissionEnabled", false); // 关闭地理位置定位 user_pref("geo.enabled", false); user_pref("geo.provider.network.url", ""); // 不主动发送会话历史给推荐系统 user_pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); user_pref("browser.newtabpage.activity-stream.feeds.snippets", false); // 设置 referer 策略,降低来源信息泄露 user_pref("network.http.sendRefererHeader", 0); user_pref("network.http.referer.XOriginPolicy", 2); // 关闭剪贴板事件,防止页面在后台读取复制行为 user_pref("dom.event.clipboardevents.enabled", false);这些参数的作用我逐个说一下。
privacy.resistFingerprinting是 Firefox 内置的反指纹总开关。开启后,浏览器会用统一值替代大部分可枚举的设备信息,并且会对 Canvas、WebGL、Audio 数据做噪点处理。它的影响面很大,很多原本能拿到的精确值会变成模糊值,这也是我建议用独立 profile 的原因之一。letterboxing会把窗口尺寸调整成固定网格的整数倍,避免网站通过window.outerWidth和screen.availWidth的差值反推真实屏幕大小。这个行为在较新的 Firefox 里随总开关默认生效,我这里显式写出来是为了防止有人单独关闭它。
webgl.disabled比较激进,直接放弃 WebGL 能力。如果你日常要看 3D 可视化或者玩网页游戏,可以先不关,靠 resistFingerprinting 自带的 WebGL 噪点应付;如果追求最大确定性,就关掉。我的使用场景很少依赖 WebGL,所以选择关闭。media.eme.enabled的关闭会影响部分视频网站的加密播放,后面第 4 章会细说。
遥测相关参数主要是关闭向 Mozilla 上报使用数据的通道,对反指纹没有直接关系,但能减少一些网络层面的特征请求,顺手就关了。地理位置和剪贴板事件也是同理,不开白不开。
再强调一次:user.js不是越全越好。每一条配置都会带来兼容性成本,建议分阶段开启,跑一段时间再决定要不要加严。下面把关键参数整理成表格,方便对照:
| 配置项 | 作用 | 风险 |
|---|---|---|
| privacy.resistFingerprinting | 系统级反指纹,统一设备信息并加噪 | 部分站点校验异常 |
| privacy.resistFingerprinting.letterboxing | 窗口尺寸信箱化 | 无明显副作用 |
| webgl.disabled | 完全禁用 WebGL | 3D 可视化页面不可用 |
| geo.enabled | 禁用地理位置 | 地图定位类功能失效 |
| network.http.sendRefererHeader | 控制 Referer 发送 | 某些防盗链图片可能加载失败 |
3.3 扩展搭配:隐私保护组合拳
如果只用官方设置,仍然会留一些尾巴,所以我会再配上几个固定扩展。这里的原则是少而精,不是越多越好。
第一推荐是 uBlock Origin。它拦截广告脚本和追踪器的能力非常强,性能开销极小,规则库更新也勤。这个扩展几乎没有替代方案。第二是 NoScript,默认拦截 JavaScript。这个扩展比较硬核,日常浏览会遇到页面白屏,需要手动放行;我一般是针对不熟悉的站点开启默认拦截,常用站点全放行,配合白名单用。第三是 CanvasBlocker,它可以在 Firefox 内置反指纹基础上,对 canvas 读取做更细的“放行、伪装、阻断”控制。如果已经依赖 resistFingerprinting,这个扩展不一定需要;想按站点放行部分绘图操作时,它很有用。第四是 Firefox Multi-Account Containers,用来把不同站点的会话隔离进独立容器,比如工作、购物、社交各用一个容器,能够进一步切断跨站追踪路径。
我不太推荐装“全家桶”式的隐私扩展,比如某些声称“一键加密浏览”的插件。这类插件往往只改了 User-Agent 就宣称保护隐私,实际效果非常有限,还容易与 uBlock Origin 的过滤规则冲突。
3.4 怎么验证隐形效果
配置完之后,最重要的一步是验证。我每次调整配置,都会去跑一遍指纹检测页面,记录前后变化。这里以 browserleaks 这类公开的指纹检测站点为例,操作流程分三步。
第一步,找一个能显示完整指纹信息的检测页面,先记录一个“基线”,也就是未开配置时报出来的值。第二步,开启 camofox 配置,刷新同一个页面,对比信息量差异。第三步,来回切换几个不同 profile,看看它们之间是否还能被区分。
我实测下来的效果很明显。未配置时,页面能直接读出显卡渲染器型号、系统字体列表、时区、屏幕分辨率;配置之后,这些值要么变成了统一的默认值,要么变成了带噪点的近似值,而且前后两次刷新还有细微差别。也就是说,站点拿到的不再是一把终身不变的钥匙,而是一把每次都在略微变化的钥匙,很难再把指纹关联到同一个人的长期行为上。
不过这里要提醒一句:指纹保护不等于网络出口不留痕迹。反指纹解决的是“设备身份”问题,网络层的出口 IP 仍然会暴露大致地理位置和运营商。如果隐私需求真的极高,你需要另做网络层的隔离方案,但那已经超出浏览器配置的范畴,这篇文章不展开。
4. 兼容性排查:我踩过的那些坑
4.1 账号登录和支付类站点异常
我遇到的第一类问题,是登录和支付类站点突然“不认识我了”。具体表现是:登录后跳回首页仍显示未登录,支付页面提示环境异常,或者反复弹出滑块验证。
原因主要有两个:一是 resistFingerprinting 会让浏览器报告的时区和语言变成统一值,与账号之前记录的环境差异太大,触发风控;二是站点的验证码脚本在读 Canvas 或 WebGL 指纹时拿到了一串“假的、不稳定”的数据,脚本校验直接失败。
我的处理方式是:不要为这一类站点修改全局参数,而是把它们隔离到一个单独的容器或 profile 中,使用相对正常的配置。日常浏览用严格配置,登录和支付用另一个宽松配置,两边互不干扰。这比在全局配置里“打洞”更容易维护,也避免了一个站点开白名单导致所有站点都享受宽松待遇。
4.2 视频卡顿与页面渲染异常
第二个常见问题是视频播放和 WebGL 相关的页面异常。关掉 WebGL 之后,部分地图类、可视化类页面直接白屏;一些视频网站也会回退到低兼容性播放逻辑,画面模糊或无法切换清晰度。
排查思路很简单:先用一个干净的 profile 加载同一页面,如果不异常,再把 user.js 按区块二分开启,定位是哪一条配置引发的。我在实践中发现,大部分视频播放问题与media.eme.enabled = false有关,因为部分站点的视频解密依赖这个组件,关掉之后加密内容无法解码。如果你经常看视频,建议保留media.eme.enabled为默认值,只靠 resistFingerprinting 做其他保护即可。
4.3 扩展之间的冲突与指纹测试结果不一致
第三个坑来自扩展之间的互相干扰。最开始我同时装了 uBlock Origin、CanvasBlocker 和 NoScript,结果指纹检测页面有时显示字体列表为空,有时又显示完整字体列表,前后不一致。排查了半天才发现,是 NoScript 拦截了字体探测脚本,而 CanvasBlocker 又对 Canvas 做了伪装,两个扩展叠加产生了不确定的中间状态。
这类问题没有一键修复的办法,只能逐个开关扩展来定位。我的建议是:扩展组合保持最小化,Firefox 自带的 resistFingerprinting 已经覆盖了大部分反指纹需求,扩展只做补充,不要叠床架屋。
4.4 问题速查表
把日常维护中遇到的高频问题整理成下面的速查表,排查的时候直接对照。
| 现象 | 常见原因 | 解决办法 |
|---|---|---|
| 登录后跳回未登录 | 时区、语言、屏幕参数与之前差异过大 | 用宽松配置的容器处理登录站点 |
| 支付页提示环境异常 | 指纹带噪点,风控脚本校验失败 | 登录与支付放到独立容器 |
| 视频无法播放或回退清晰度 | media.eme.enabled=false 导致解密失效 | 放开 media.eme.enabled |
| 地图、3D 页面白屏 | WebGL 被禁用 | 临时换用一个宽松 profile,或打开 webgl |
| 指纹检测结果前后不一致 | 扩展叠加产生不确定状态 | 减少扩展数量,保留核心组合 |
| 图片防盗链失效 | Referer 被裁剪 | 按站点调整 referer 策略 |
最后再分享一点维护上的心得。camofox-browser 这个项目做下来,我最大的体会是:隐私保护不是“开一个开关”就结束的事情,而是一条持续迭代的路。浏览器在更新,网站的检测技术在更新,你的配置也不可能一劳永逸。我通常每两周会花半小时做一次例行维护:拉取最新版 Firefox 更新说明,看看有没有影响现有配置的改动;跑一次指纹检测,对比各项指标;检查扩展是否发布了可能导致行为变化的新版本。这套节奏坚持下来,项目才能一直保持在可用状态。
如果你也想跟着搭一套,路径可以很简单:先建独立 profile,从开启privacy.resistFingerprinting和letterboxing开始,跑一周,看能不能接受遇到的兼容性问题,再逐步加严。不用一开始就追求“最强隐身”,先保证“不被广告平台一眼认出”,就已经赢了一大半。