
1. 项目缘起为什么我会盯上“伪装”这个方向做隐私保护这个方向有年头了。以前我总跟人强调你要用隐私模式、要装拦截插件、要关掉cookie。直到有次给朋友做安全测试发现他的浏览器即便开了隐身窗口访问某个页面时依然能被对方精准识别出来——甚至连我之前访问过哪些站点都能被推算个七八分。那次之后我就明白了一个道理浏览器本身的“长相”太固定了固定到可以被当身份证用。camofox-browser这个项目的思路就是从这里长出来的。它不是一个从零开始写的浏览器而是一套基于Firefox的深度改造方案核心目标就一个让不同用户用起来浏览器在服务端眼里长得完全不一样甚至让同一个人在不同时间打开看起来都像不同的机器。如果你正在做反爬研究、账号隔离、隐私保护或者单纯不想让广告联盟把你在不同站点之间的行为串起来那么这个项目的基本思路会非常对胃口。GitHub上叫这名字的项目有好几个分支有的偏指纹伪装有的偏容器隔离我自己实践的这套组合是“Firefox内核 强指纹随机化 多容器会话隔离”下面拆开讲。1.1 为什么选Firefox而不是Chrome系先回答一个绕不开的问题市面上浏览器这么多为什么偏偏用Firefox做底子第一个原因很现实Chromium系的指纹一致性太强了。Chrome、Edge、Brave、Opera全都是Blink内核JavaScript引擎也是同一个底子它们暴露出来的API结构高度雷同。这种统一带来的问题是——一旦爬虫或风控系统抓到某个特征所有Chromium系浏览器一锅端全被识别。Firefox用的是Gecko内核本身就属于少数派特征面更小伪装起来调整空间更大。第二个原因更关键Firefox提供了一个官方内置的隐私开关就是privacy.resistFingerprinting。这个开关一旦打开Firefox会主动把很多指纹收集接口返回的数据做统一化处理比如把 Canvas、WebGL 的读取结果加噪把时区强制按UTC算。Chrome 想做到同等效果得靠第三方插件硬改API效果还没有Firefox原生来得干净。第三个原因纯粹是工程上的Firefox的about:config几乎把所有内部机制都暴露出来了可以做细颗粒度调参。而Chromium系的策略开关要么不存在要么被企业策略锁死个人做深度定制的空间非常小。1.2 这套方案到底解决什么问题我见过太多人把“指纹伪装”理解成“改个User-Agent”。真不是。User-Agent是最好改的也是最容易被交叉验证识破的。你UA改成Chrome但navigator.plugins还是Firefox那套对方用个十几行的脚本就能拆穿你。camofox-browser这套组合拳真正处理的是指纹的链路完整性问题。什么意思就是当你暴露给网站的每一个信息点不管是UA、Canvas、WebGL、时区、语言、字体、硬件并发数还是更细的AudioContext、屏幕色彩深度、DevTools是否开启它们之间必须互相自洽。一个伪装方案如果不考虑自洽性伪装得越多漏洞越多。这套方案解决的典型场景包括一个浏览器同时管理多个平台的账号互不串号反爬测试中模拟不同用户环境来验证风控规则的准确性个人隐私保护避免不同站点之间通过指纹交叉关联你的浏览行为这里需要说清楚我完全不建议把这项技术用在绕过账号封禁、批量注册、欺诈这种灰色领域。指纹伪装不是用来做恶的它首先是用户保护自己信息自主权的工具。2. 核心设计思路伪装不是“改”而是“演”2.1 浏览器的“长相”由什么决定在动手配置之前先得搞清楚一个网站的指纹采集脚本到底在看什么。这里我列一个典型的风控系统会采集的信息全景采集维度具体内容迷惑难度HTTP请求头User-Agent、Accept-Language、Accept-Encoding、Sec-Fetch-*简单JavaScript属性navigator.userAgent、platform、language、languages、hardwareConcurrency、deviceMemory简单渲染指纹Canvas画布哈希、WebGL渲染器信息、屏幕分辨率、色深、窗口尺寸中等音频指纹AudioContext处理音频样本后产生的哈希中等字体指纹通过CSS和canvas检测已安装字体列表中等环境指纹时区偏移、本地时间、语言偏好简单存储特征localStorage的空键名、IndexedDB是否可用、Cookie启用状态简单网络特征WebRTC本地IP泄露、TCP/IP协议栈特性复杂你注意看这个表。第一二行是基础款大部分伪装工具都能做。但真正麻烦的是第三行往下因为Canvas和WebGL的渲染结果取决于你设备的GPU、显卡驱动、操作系统版本、字库它带有极强的硬件指纹属性。同一台电脑上用同一个浏览器装不同的伪装插件如果Canvas哈希完全一样风控系统立刻就知道你只是改了表层参数。2.2 从“一致”到“随机”的思维转换我踩过最大的一个坑是追求“伪装成另一台固定设备”。比如把自己伪装成一台Windows 11 Chrome 120 常见笔记本配置。这个思路听起来很合理但实际操作中会遇到一个致命问题你无法穷举这台“虚拟设备”的所有软硬件细节。你伪装了UA是Chrome但navigator.vendor依然是Mozilla你伪装了WebGL的显卡型号是NVIDIA RTX 3060但屏幕分辨率还是你笔记本的2560x1600色深依然是你实际的数值你甚至把这些都改了但浏览器的navigator.platform忘记动又露馅了。伪装成特定设备这条路补丁永远打不完。后来我换了思路与其伪造一个固定的虚假身份不如每次会话都生成一个随机的、自洽的全新身份。就像一个人换了一身完全不同的行头和口音去另一个城市生活而不是在同一座城市假装成另外一个人。每次启动浏览器时自动生成一套完整的“人设”包括UA、语言、时区、Canvas加噪参数、WebGL参数、硬件并发数、屏幕尺寸、字体列表这些参数之间存在联动关系由模板引擎生成保证互相不矛盾。2.3 指纹随机化的自洽性约束要让随机化真正有效必须做交叉一致性校验。比如如果你生成的身份是macOS那navigator.platform应该是MacIntelnavigator.oscpu也应该是对应的版本而UA中不应该出现“Windows”字样如果你生成的身份是Windows那navigator.maxTouchPoints大概率是0因为绝大多数Windows笔记本的触摸屏支持多点触控这个数值并不固定但至少不能是iPhone那种5点触控的典型值时区选择了东京那navigator.language最好包含jaAccept-Language头也应该把日语排在前面分辨率选择了1920x1080那window.outerWidth和window.innerWidth的差值要符合操作系统窗口边框的正常范围这些约束看着琐碎但它们正是指纹指纹法检测的突破点。所谓“高级风控”从来不是看单一维度而是把所有维度拉出来做综合评分。你单项伪装得再像只要有一处不自洽评分模型就会把你标记为高风险。2.4 为什么需要“会话隔离”配合指纹伪装解决的是“看起来像谁”的问题容器隔离解决的是“同一套浏览器里不同身份之间不串味儿”的问题。很多人在一个浏览器里装多个指纹插件以为切换指纹就能切换身份。但实际上呢浏览器里存的Cookie、localStorage、IndexedDB、HTTP缓存、Service Worker这些东西会把你的操作痕迹串起来。你在这个标签页用身份A登录了某个账号切到身份B的标签页时虽然navigator.userAgent变了但网络层携带的Cookie依然是身份A的对方用一次请求就能看出这两个“人”来自同一个浏览器实例。Firefox的Multi-Account Containers容器扩展本质上是用独立的cookie store来隔离不同会话。我在camofox-browser项目里把这个机制进一步强化了每个容器不仅隔离Cookie还隔离localStorage、IndexedDB、HTTP缓存、Service Worker注册表。这样配置之后身份A和身份B在浏览器层面就像两台互不相关的机器。3. 实操配置从Firefox到camofox-browser现在开始讲具体操作。下面这个流程是基于我在Ubuntu 22.04和Windows 11两套环境上都验证过的方案你按顺序走一遍基本就能得到一个可用的“伪装浏览器”。3.1 基础版本选择与安装先说版本选择。Firefox有两个通道普通版和ESR版。做指纹伪装我强烈建议选ESR版也就是Extended Support Release。原因很简单ESR版本每42周才做一次大版本更新中间只打安全和兼容性补丁——你辛辛苦苦调好的指纹参数不会因为Firefox两周一次的版本更新而被意外重置或改变行为。# Ubuntu/Debian下安装Firefox ESR # 先把Mozilla的APT源加进来 sudo install -d -m 0755 /etc/apt/keyrings wget -q https://packages.mozilla.org/apt/repo-signing-key.gpg -O- | sudo tee /etc/apt/keyrings/packages.mozilla.org.asc /dev/null echo deb [signed-by/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main | sudo tee /etc/apt/sources.list.d/mozilla.list sudo apt-get update sudo apt-get install firefox-esrWindows用户就更简单了直接去Mozilla官网下载Firefox ESR安装包安装时选择“为所有用户安装”即可。安装完之后先不要急着用接下来要做的是把默认配置改掉。3.2 关键偏好配置about:config逐项调优在地址栏输入about:config回车之后搜索下面这些项逐一修改。这些是我经过几十轮测试后留下来的配置组合每一项都有它的作用。# 基础隐私加固 privacy.resistFingerprinting true privacy.resistFingerprinting.letterboxing true privacy.trackingprotection.fingerprinting.enabled true privacy.trackingprotection.cryptomining.enabled true privacy.clearOnShutdown.offlineApps true # 禁用WebRTC地址泄露 media.peerconnection.enabled false media.peerconnection.ice.default_address_only true # 禁用遥测和数据上报 datareporting.healthreport.uploadEnabled false datareporting.policy.dataSubmissionEnabled false toolkit.telemetry.enabled false toolkit.telemetry.unified false toolkit.telemetry.server data:, # 禁用搜索建议和网络请求外泄 browser.search.suggest.enabled false browser.urlbar.suggest.searches false browser.safebrowsing.enabled false browser.safebrowsing.malware.enabled false # 阻止混合内容降级 security.mixed_content.block_active_content true这里重点讲一下privacy.resistFingerprinting.letterboxing这个参数。它是配合resistFingerprinting一起用的作用是当你调整浏览器窗口大小时Firefox不会把你真实的窗口内部尺寸暴露出去而是把窗口内容区缩放到一个“标准化”的尺寸范围内。这个设计妙在它不伪造一个固定分辨率而是让每次窗口resize都产生一个随机但合理的尺寸风控系统拿到手的数据每次都不一样根本无法建立稳定的特征关联。3.3 Canvas与WebGL指纹的随机加噪privacy.resistFingerprinting本身已经会对Canvas和WebGL渲染结果做加噪处理但默认的噪声强度对高精度指纹采集来说不够。我在项目里进一步安装了一个内部自研的扩展对Canvas的toDataURL、getImageData以及WebGL的readPixels做了一层拦截每次调用时注入像素级微噪。直接用Firefox内置的canvas图片读取接口就能验证加噪效果。下面这段脚本可以测试当前浏览器的Canvas指纹稳定性// 粘贴到浏览器控制台运行两次运行结果应存在差异 const canvas document.createElement(canvas); canvas.width 200; canvas.height 200; const ctx canvas.getContext(2d); ctx.textBaseline top; ctx.font 14px Arial; ctx.fillStyle #f60; ctx.fillRect(0, 0, 100, 100); ctx.fillStyle #069; ctx.fillText(camofox-test, 5, 5); ctx.fillStyle rgba(102, 204, 0, 0.7); ctx.fillRect(30, 30, 50, 50); const dataURL canvas.toDataURL(); console.log(Canvas指纹:, dataURL); // 做一个简单哈希 let hash 0; for (let i 0; i dataURL.length; i) { const char dataURL.charCodeAt(i); hash ((hash 5) - hash) char; hash | 0; } console.log(Canvas哈希:, hash);正常情况下同一台机器、同一个浏览器、相同配置这个哈希值每次执行都应该完全一致。如果加了resistFingerprinting和Canvas加噪扩展每次刷新页面执行这个脚本哈希都不同说明伪装生效了。3.4 User-Agent与语言偏好的模板化生成UA的随机化我建议用一种半自动的方式处理而不是完全随机。完全随机的问题是容易出现“Windows UA macOS平台属性”这种自相矛盾。我的做法是预设几个平台模板每次启动时随机选一个| 模板 | User-Agent示