1. camofox-browser 的项目定位:一台“会伪装”的 Firefox,而不是一个新浏览器
很多人以为浏览器默认状态就是“能用就行”,但真正把浏览器的隐私行为测过一遍之后,你很难再这么想。网站通过 Canvas 绘图、音频处理、字体枚举、屏幕分辨率、硬件并发数、插件列表等信息,可以拼凑出一台设备几乎唯一的指纹;你在普通浏览器里访问过的每个页面,都在悄悄完成这种身份画像。我启动 camofox-browser 这个项目,就是想给自己一个“默认状态就用得住”的浏览器环境:默认抵抗指纹追踪、默认隔离站点数据、默认清理会话痕迹,而且所有配置都能像代码一样被版本管理、随时复现。
camofox-browser 不是从零写浏览器内核,而是把 Firefox 当作底座,通过 user.js 预配置文件、policies.json 企业策略,以及极少量经过筛选的扩展,完成三层目标。第一层,让浏览器停止主动向厂商上报行为数据;第二层,让浏览器对外暴露的指纹信息尽量普通且稳定;第三层,让不同业务身份之间的数据自动隔离,防止网站之间串门。简单说,它更接近“Firefox 的隐私发行版”,或者“浏览器加固工程”,而不是传统意义上的套壳浏览器。
这个项目适合三类人。一类是像我一样需要同时登录多个后台系统、处理不同业务身份的人,希望每个身份之间互不干扰。第二类是安全测试和隐私研究从业者,他们需要一套可复现、可审计的浏览器基线,而不是靠手动点选维护的临时环境。第三类是普通用户里愿意花半小时为自己争取隐私空间的人。如果你希望“尽量减少广告跟踪、防跨站识别、不随便泄漏设备信息”,那下面这套做法可以直接抄作业。
1.1 默认浏览器到底在“大方地让渡”什么信息
我最早被刺激到,是因为一次简单的检测。用一个本地 HTML 页面读取navigator对象、Canvas 渲染结果和已安装字体,不到半秒钟,页面就能生成一个 32 位的哈希值,并且连续刷新十次结果几乎一致。这就是指纹的雏形。更麻烦的是,浏览器还会把时区、语言、屏幕尺寸、操作系统内核版本、CPU 并发数这些信息一并暴露给 JavaScript。单看每一项,似乎都算不上隐私;但组合起来,识别率可以做到相当惊人。同时,浏览器自身还会上报遥测数据、远程配置开关状态、基于兴趣的内容推荐行为;这些数据虽然不直接等同于“密码泄露”,但都在帮助厂商和第三方构建你的行为画像。camofox-browser 的首要任务,就是把这些默认“大方让渡”的信息重新收回来。
1.2 项目边界:只做追踪对抗与身份隔离,不承诺极端匿名
做这个项目之前,我先把目标边界想清楚了。camofox-browser 要解决的是商业追踪、广告网络、普通风控和跨站身份拼图这一类问题。它不是也不可能是“完全隐身”的工具,更不承诺对抗专业级别的网络侦查。如果对自己的要求是“最好没人知道我在访问什么”,那需要的不是浏览器配置,而是一整套完全不同的网络链路和操作习惯,那超出了浏览器工程的范畴。把边界定清楚很重要,因为很多隐私项目恰恰死在“什么都想做”上:又要防指纹,又要匿名,又要兼容所有网站,最终一样都没做好。camofox-browser 只做三件事:少上报、防读取、强隔离。听起来朴素,但这三件事分别对应数据采集的三个环节,做好了,商业追踪基本就断了大半。
2. 选型复盘:为什么 Firebase 底座比 Chromium 套壳更适合“伪装”需求
2.1 内核能力差距:容器隔离与 Total Cookie Protection 是刚需
伪装和隔离是两件事。伪装是让网站读取指纹时得到一套“不会出卖你”的信息;隔离是让 A 网站即使拿到了信息,也无法和 B 网站的数据拼在一起。Firefox 内建的容器功能很早就存在,它允许把不同标签页放进互相隔离的存储分区,每个容器拥有独立的 Cookie、localStorage 和 IndexedDB。我可以在同一个浏览器窗口里同时登录两个不同的账号,两边互不知道对方存在。Chromium 系浏览器默认没有同等开放的容器机制,想实现类似效果往往要借助“创建多个独立配置文件”或者依赖第三方扩展,隔离粒度和管理体验都差不少。
另一个关键项是 Firefox 的 Total Cookie Protection。这个机制会把 Cookie 按站点域名做分区,第三方 Cookie 不再是一个共享数据库,而是被“锁”在发起请求的网站域下。举个例子:如果我的购物网站里嵌入了一个社交平台按钮,社交平台拿到的 Cookie 只能作用于它自己的第一方域,无法读取我在购物网站里的身份信息。跨站追踪的本质就是靠第三方 Cookie 串起不同站点的身份,而这一机制从浏览器底层把串门通道堵住了。对于 camofox-browser 这样的隐私项目来说,这种内建能力比任何扩展都靠谱。
2.2 工程化代价:配置工程比重新编译更可持续
选择 Firefox 而不是 Chromium,还有工程维护层面的考量。基于 Chromium 改一个“隐私浏览器”,技术上并不算难,难的是后续维护。Chromium 底层有大量遥测和自动更新机制深度绑定厂商体系,要去除干净需要投入持续的构建和测试资源,普通个人项目很难承受。Firefox 这边则可以把绝大部分隐私开关直接暴露在about:config里,通过一个 user.js 文件统一管理;浏览器升级后,这些配置通常依然生效。camofox-browser 的核心产物因此不是一份几 GB 的源码工程,而是几百行配置加一份扩展白名单。任何人都能审查、修改、重新分发,甚至可以把这个配置工程直接拿来作为自己团队的浏览器基线。
当然,Firefox 也有它的短板。部分指纹相关项,比如 WebRTC 的本地地址暴露风险,虽然可以配置,但默认形态不如某些硬核浏览器激进。另外,Firefox 官方扩展市场里的扩展质量参差不齐,我在筛选扩展时比找配置项谨慎得多。这些短板不影响总体选择,但让我在做方案时更清楚:哪些坑该绕,哪些坑只能填。
3. 第一层防线:先让浏览器停止“主动汇报”,再谈伪装
3.1 关闭遥测与数据上报的关键开关
很多隐私浏览器项目只盯着指纹,却忽略了一个更基础的问题:浏览器厂商自己也在收集用户行为数据。Firefox 默认开启遥测功能,虽然可以被用户关闭,但在默认状态下,一些使用数据仍然会被收集。camofox-browser 的第一步,就是把遥测和主动上报渠道全部关掉。我维护的 user.js 里固定包含这些项:
| 配置项 | 推荐值 | 用途 |
|---|---|---|
toolkit.telemetry.enabled | false | 关闭基础遥测 |
datareporting.healthreport.uploadEnabled | false | 关闭健康报告上传 |
datareporting.policy.dataSubmissionEnabled | false | 关闭政策数据提交 |
app.normandy.enabled | false | 禁用远程配置服务 |
browser.discovery.enabled | false | 关闭内容推荐数据采集 |
network.allow-experiments | false | 避免参与实验特性网络 |
这里要提醒一个容易忽略的点:很多配置项需要重启浏览器才会彻底生效,而且新版 Firefox 偶尔会新增遥测类别,旧配置项的名字可能被移除或改名。所以每次升级主版本后,我都习惯在about:config里搜一下telemetry和reporting关键词,看有没有新冒出来的开关。这个习惯比一次配置永久放心重要得多,因为浏览器不是静态软件,它每个版本都在变化。
3.2 默认行为改造:HTTPS、会话恢复与登录信息
除了遥测,还有几个默认行为会明显影响隐私边界。第一个是 HTTPS 优先模式,我把它强制开启,dom.security.https_only_mode设为true;如果希望只在隐私窗口生效,也可以只开dom.security.https_only_mode_pbm。这样绝大多数场景都会优先走加密通道,避免明文内容暴露。第二个是会话恢复的隐私级别,browser.sessionstore.privacy_level我设置为2,浏览器崩溃后恢复标签页时,不会恢复表单输入内容,降低内容泄漏风险。第三个是登录信息保存,signon.rememberSignons按需关闭;如果希望做到“关闭即失忆”,建议干脆不让浏览器保存账密明文,密码统一交给独立密码管理器,浏览器完全不碰这层数据。
这些改造听起来不如“指纹伪装”酷,但它们是整套隐私模型的地基。如果浏览器一边高调伪装指纹,一边把使用日志上报给厂商,那伪装就失去了意义。地基不打牢,上面盖多漂亮的伪装层都是白搭。
4. 核心伪装层:让浏览器指纹“普通且稳定”,而不是“每次都在变”
4.1 Canvas 与 WebGL 指纹:禁用不是最优解
网站识别设备最经典的手段之一,是让浏览器绘制一张隐藏的画布图片。不同显卡、不同操作系统、不同字体渲染引擎绘制出的像素数据会有细微差别,这段数据经过哈希后就变成稳定的设备指纹。WebGL 也是一样,GPU 型号和渲染参数能被 JavaScript 读取。
对于这类指纹,很多人的第一反应是直接禁掉 JavaScript 读取 Canvas。实际试过之后你会发现,大量功能会被误伤:在线设计工具、动态图表库、部分验证码组件,都需要读取 Canvas 才能完成交互。完全禁用几乎等于把一半网站打成白屏。我的做法是使用 CanvasBlocker 扩展,把读取模式设为“伪装”而不是“禁止”。在伪装模式下,页面拿到的依然是一份画布数据,但不是真实设备生成的,而是扩展模拟出来的稳定值。这样既保留兼容性,又破坏了基于真实数据建立的指纹。之后给可信站点开白名单,比如自己的博客和常用后台,保证正常交互功能不受影响。WebGL 方面我同样采用“隐藏信息而不是禁用”的思路,因为地图、3D 展示、可视化大屏都依赖它。如果你的工作流对图像处理要求高,建议给 WebGL 干扰也做成分域白名单,不要全局一刀切。
4.2 RFP 模式:Firefox 自带的“指纹抵抗”为什么值得开
Firefox 有一个被很多隐私项目忽视的大钥匙——privacy.resistFingerprinting。开启这个项之后,浏览器会在后台做几件统一化的事:Canvas 读取结果被加入统一噪声、暴露给页面的字体数量被限制、时区统一、屏幕分辨率和窗口尺寸信息被模糊化、硬件并发数被取整。一句话概括:让所有用户的“视角”都变得差不多,个体指纹自然就融进人群里了。我建议把 RFP 放在指纹伪装的第一优先级,扩展层只做补充,因为它是浏览器原生实现的,覆盖面广,而且不依赖某个扩展是否长期维护。
开启 RFP 有两个副作用需要提前知道。第一,部分网站的时间显示会变成 UTC,因为页面读取的本地时区被干扰了;解决方法通常是接受这种显示差异,或者在页面里手动设置显示时区。第二,CSS 媒体查询中的某些设备参数会被“普通化”,极端布局下可能出现滚动条变宽或字体渲染变化。整体来说,收益远大于代价。
4.3 字体与 UA:别为了“更伪装”而主动制造漏洞
字体指纹的原理是读取document.fonts或通过测量字符串宽度来判断系统安装了哪些字体,组合出的字体列表在人群中有很强的区分度。很多隐私配置会直接禁止字体枚举,或者返回一份伪造的字体列表。我的经验是:字体列表要“稳定地限量”,不要“每次随机更换”。选一套常见字体组合固定返回,比如微软雅黑、宋体、Arial、Segoe UI 这类大众字体,既保证中文网页观感,又不会让网站在统计上识别出“一台每次打开字体都不同的奇怪设备”。
User-Agent 则是需要谨慎对待的一项。除非你是做自动化测试,否则强烈不建议在普通浏览器里魔改 UA。原因很简单:很多站点的服务端不只依赖 UA 字符串,还会结合网络层特征一起判断。你只改 UA 而其他特征没变,反而会造成“逻辑不自洽”,更容易触发风控。camofox-browser 的策略是保留 Firefox 官方 UA,不折腾这一层;真正需要切换身份时,依靠容器隔离和独立配置文件完成,而不是靠 UA 字符串。
5. 身份隔离与生命周期:把不同身份放进“隔间”,用完即走
5.1 多账户容器的组织方式:工作、购物、社交各住各的房间
指纹伪装负责让网站“认不出你”,容器隔离则负责让网站“串不起你”。Firefox Multi-Account Containers 扩展是我默认推荐的扩展之一,用法很直接:为不同场景建立不同容器,比如“工作”“购物”“银行”“社交”“默认”。每个容器拥有独立的 Cookie、缓存和站点数据,相当于同一台浏览器里住了好几户人家,每户只负责访问一类站点。
实际使用里,我会把经常一起出现的业务放进同一个容器,尽量少混。比如登录技术社区和开发文档站时用“工作”容器;购物和支付网站固定用“购物”容器,并让支付域名也强制在购物容器内打开。Multi-Account Containers 支持配置“特定站点总是在某个容器中打开”,这一点非常实用。设置好后,打开支付页面时自动进入购物容器,不会再手滑把支付身份暴露在别的容器里。需要注意的是,容器之间不共享书签和历史,这是正常现象,也是隔离的意义所在。
5.2 关闭即清理:Cookie、缓存与离线数据的生命周期管理
隔离解决“空间问题”,清理机制解决“时间问题”。我理想中的状态是:浏览器关闭后,大多数站点数据立刻消失,只有我主动指定的一小部分身份保持登录。实现方式是启用privacy.clearOnShutdown系列选项,让浏览器退出时自动清理数据。可以参考这组配置:
privacy.clearOnShutdown.cache=trueprivacy.clearOnShutdown.cookies=trueprivacy.clearOnShutdown.history=trueprivacy.clearOnShutdown.offlineApps=trueprivacy.clearOnShutdown.sessions=trueprivacy.clearOnShutdown.openWindows=false
如果完全清理,意味着所有网站的登录状态都会丢失。对需要长期保持登录的网站,可以用 Cookie Auto Delete 这类工具做白名单管理:标记为信任的站点关闭后仍保留 Cookie,其余站点一律删除。更优雅的方式是结合容器,因为清理规则可以按容器配置。比如默认容器每次清空,工作容器保留一周。这套“短期默认存疑、长期明确授权”的模型,是我试过之后觉得最舒服的平衡点;既保住了便利性,又不给跨站追踪留下太多温床。
6. 把配置固化成可复现项目:user.js、policies.json 与自动化校验
6.1 user.js:让 about:config 变更变成版本库里的文本
手动在 about:config 里点开关,最大的问题是不可复制。换一台电脑就要重新点一遍,而且容易漏项。camofox-browser 的做法是把所有配置写进 profile 目录下的 user.js,Firefox 启动时自动读取。文件内容就是一行行user_pref("配置名", 值);,注释写清楚每行的目的。下面是节选:
// camofox-browser/user.js 节选 // 关闭遥测与数据上报 user_pref("toolkit.telemetry.enabled", false); user_pref("datareporting.healthreport.uploadEnabled", false); user_pref("datareporting.policy.dataSubmissionEnabled", false); // 开启指纹抵抗 user_pref("privacy.resistFingerprinting", true); // 退出时清理 user_pref("privacy.clearOnShutdown.cookies", true); user_pref("privacy.clearOnShutdown.cache", true); user_pref("privacy.clearOnShutdown.history", true);注意,user.js 只在浏览器启动时被读取一次,修改后必须完全重启浏览器才能生效。另外,不要把它和prefs.js搞混。prefs.js是运行时生成的实时状态文件,随时会被浏览器覆盖;user.js才是“每次启动时写入默认值”的入口。把这个文件放进项目的版本库里,别人克隆后直接替换到自己的 profile 目录,就能得到几乎一致的浏览器环境。这也是整套工程最值得复用的一部分。
6.2 policies.json:把关键项锁死,避免配置被随手改回去
user.js 对愿意配合的人非常有效,但它拦不住“手动去 about:config 里把某条配置改回去”的冲动。如果要把 camofox-browser 分发给团队或客户,建议再叠加一层企业策略文件policies.json。这个文件放在 Firefox 安装目录的distribution文件夹下,优先级高于 user.js,普通用户无法在界面上或 about:config 里绕过策略设置的选项。一个简单示例:
{ "policies": { "DisableAppUpdate": true, "DontCheckDefaultBrowser": true, "SearchEngines": { "Default": "DuckDuckGo" }, "ExtensionSettings": { "uBlock0@raymondhill.net": { "installation_mode": "force_installed", "install_url": "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi" } } } }这个文件非常适合作统一部署:禁自动更新、固定默认搜索引擎、强制安装必要扩展。个人项目则不必层层加锁,因为锁太多也会给自己带来不便。我的建议是:自己用,user.js 足够;要作为跨设备分发项目,再把 policies.json 纳入进来。
6.3 自动化校验:版本升级后排查配置是否仍然生效
配置写得多,不代表每条都生效了。Firefox 升级后,某些旧配置项可能被重命名或删除,而 user.js 里不会报错,只是悄悄不生效。我增加了一个简单的回归流程:每次升级浏览器后,在 about:config 里搜索user.js,Firefox 会标记出哪些项来自 user.js、哪些被用户运行时修改。花五分钟过一遍这个列表,清理掉已经不存在的旧配置项,再把新增的隐私选项补充进 user.js。对于批量部署的场景,也可以写脚本读取 user.js 中的配置名,逐一检查浏览器配置文件里的最终值。这个习惯虽然繁琐,却能让整套加固基线长期保持在可用状态。
7. 实测避坑记录:这些“过度优化”差点让我放弃这个项目
7.1 动态伪装变成“验证码吸引器”
项目早期,我加了一套“每次启动随机生成新指纹”的自动化方案。理论上每次都是新面孔,商业追踪系统无法关联。结果没用两天就崩溃了:几乎所有带风控的网站都在弹验证码,有些甚至直接提示安全检测异常。事后复盘原因很简单:真实用户在同一台设备上的屏幕分辨率、语言、字体、时区变化速度不会那么夸张;而这套方案让浏览器每次启动都在不同时区、不同语言、不同字体列表之间横跳,反而触发了异常风控模型。
最终方案改成了“固定伪装身份”:RFP 开启后,配合稳定的字体列表和统一时区,让指纹在一个普通范围内保持稳定。伪装的目标不是让追踪者“完全没法追踪”,而是让你混在一大群普通用户里,变得不值得追。这个想法的转变,让浏览器从“验证码地狱”回到了正常可用状态。
7.2 扩展装太多,隐私浏览器反而泄漏更多
另一个教训是扩展管理。第一版 camofox-browser 我装了十几个扩展,涵盖广告拦截、脚本控制、Cookie 清理、Canvas 伪装、UA 切换、防跟踪等。结果在测试指纹页面时发现,扩展注入的脚本本身也能形成新指纹,而且每个扩展都可能读取页面内容,等于给所有访问过的网站又多喂了几份数据。更重要的是,两个 Cookie 清理扩展同时生效时,登录状态会莫名其妙丢失。
现在扩展列表精简到五类以内:uBlock Origin 负责内容过滤,CanvasBlocker 负责画布伪装,Multi-Account Containers 负责身份隔离,Cookie Auto Delete 负责生命周期清理,另加一个密码管理器。原则是:能通过 user.js 和浏览器原生配置解决的,绝不用扩展解决;扩展数量每多一个,攻击面和指纹面都同步放大。
7.3 与原生 Firefox 的直观效果对比
我用自己的检测页面和实际访问体验做了一轮对比,结果节选如下:
| 检测维度 | 原生 Firefox | camofox-browser |
|---|---|---|
| 遥测上报 | 默认开启 | 已关闭,远程配置也被禁用 |
| 第三方 Cookie 跨站追踪 | 依赖默认保护 | 容器隔离加清理,跨站拼图成本显著上升 |
| Canvas 指纹 | 真实可读 | 稳定噪声值,站点拿不到真实数据 |
| 字体枚举 | 返回完整字体列表 | 返回限定后的常用字体集合 |
| 时区与语言 | 真实系统值 | 统一为固定值 |
| 关闭后残留 Cookie | 默认保留 | 按白名单清理,默认容器基本清空 |
| 日常登录便利性 | 高 | 需习惯容器和清理规则,略有学习成本 |
这不是想说 camofox-browser 天下无敌,而是说隐私浏览器靠的是“少上报、防读取、强隔离、勤清理”四个动作叠加出来的整体效果。每个动作单独看都会牺牲一点便利性,合在一起却能显著提高追踪成本。最后分享一个我自己一直用的习惯:把 camofox-browser 当“白手套”使用,只处理账号登录、支付、后台管理和需要认真隔离身份的事情;日常娱乐浏览则用普通浏览器,两个环境分工明确,便利性不会牺牲太多,真正敏感的浏览行为又能始终处在加固环境下。隐私配置这件事,最怕的不是麻烦,而是“装完就忘”;把它当成一个随版本持续维护的小项目,远比一次性调完配置更实际。