Camoufox:把指纹伪装做到 C++ 层,这个反检测浏览器想给 AI Agent 一张「真脸」
- 在C++层拦截指纹调用,避免JS注入被检测的悖论
- 按真实市场份额分布生成指纹,解决群体统计异常
- patch Juggler协议,使自动化事件走原生输入路径
- 提供兼容Playwright的Python接口,迁移成本极低
- 承认局限性:无法完全模拟Chromium,指纹一致性需持续对抗
上周有个朋友跑来做数据采集的活,给我看他的 Playwright 脚本。代码写得很工整,代理 IP 也在转,但目标站点的 Cloudflare 就是不放行,每次都卡在「正在验证您是否是真人」那个转圈页面。他换了好几个 stealth 插件,还是一样。
我让他别折腾 JS 注入了,试试 Camoufox。第二天他给我发消息,过了。
说实话,反检测浏览器这个赛道挺热闹的。商业的有 Multilogin、AdsPower、GoLogin,开源的有 puppeteer-real-browser、undetected-chromedriver、playwright-stealth。那 Camoufox 凭什么能在 Trendshift 上爬到前面,还能拿到 Scrapfly、Clover Labs 这些厂商的赞助?
我花了几天把它的仓库和文档翻了一遍,发现它做的事其实不复杂,但每一件都做到了刀刃上。这篇文章就拆给你看。
一句话定位
Camoufox 是一个基于 Firefox 的反检测浏览器,专门为网页抓取和 AI Agent 设计。
它解决的核心问题只有一个,让自动化脚本看起来像一个真实的人在一台真实的设备上浏览网页。
听起来简单,做起来全是坑。因为现代反 bot 系统早就不是看一个 navigator.webdriver 字段就放行的年代了。它会用上千个信号交叉验证你的浏览器,GPU 型号、字体列表、屏幕分辨率、时区、语言、WebRTC IP、AudioContext 采样率……任何一个对不上,你就被标记了。
Camoufox 的做法可以总结成一句话,与其在 JavaScript 层骗你,不如直接在 C++ 层改掉你。
为什么 JS 注入这条路走不通
要理解 Camoufox 的价值,得先看看传统反检测方案是怎么做的,以及为什么它们会失败。
最早大家用的是 puppeteer-extra-stealth 这类插件,思路很直接,浏览器暴露了什么可疑字段,就用 JavaScript 把它覆盖掉。比如把 navigator.webdriver 改成 false,把 navigator.platform 改成想要的值。
这条路有两个绕不开的问题。
第一个是覆盖不完整。 JavaScript 能改的东西是有限的。你改了 navigator 的 User Agent,但 HTTP 请求头里的 User Agent 没跟着改;你改了屏幕分辨率,但 window.screen 和 worker 线程里的值不一致。反 bot 系统只要做一次交叉验证,你就露馅了。
第二个是覆盖本身可以被检测。 这才是最致命的。反 bot 系统可以用 Object.getOwnPropertyDescriptor 检查属性是不是被改写过,可以用 Function.prototype.toString 看一个函数是不是还返回 [native code],可以对比主线程和 worker 线程的值是否一致。你用 JavaScript 改的任何东西,在 JavaScript 层都能被查出来。
这就形成了一个悖论,你想用 JavaScript 隐藏 JavaScript 的痕迹,但检查 JavaScript 痕迹的工具也是 JavaScript。猫鼠游戏里,老鼠永远在猫的视线内。
Camoufox 的解法,直接下沉到 C++ 层
Camoufox 的核心创新就一句话,它在 Firefox 的 C++ 实现层拦截所有指纹相关的调用。
什么意思呢?当网页通过 JavaScript 调用 navigator.hardwareConcurrency 或者 WebGLRenderingContext.getParameter() 的时候,这个调用最终会走到 Firefox 引擎的 C++ 代码里。Camoufox 直接在这一层把返回值改掉。
这样做的好处是,从 JavaScript 的视角看,这些属性本来就是这样的。没有覆盖,没有劫持,Object.getOwnPropertyDescriptor 返回的描述符是原生的,toString() 老老实实返回 [native code]。反 bot 脚本根本找不到篡改的痕迹,因为篡改发生在它够不到的层级。
这种思路不是没人想过,但做起来门槛极高。你得 fork 整个 Firefox,理解它的源码结构,找到每一个可能泄露指纹的调用点,然后打 patch。Camoufox 的仓库里维护着一整套 patch 系统,还自带一个 developer UI 让你管理这些 patch,可见工作量之大。
坦白讲,这种「改浏览器源码」的硬核路线,注定了它只能由少数有能力维护 fork 的人来做。但也正因为如此,它的隐蔽性是 JS 注入方案比不了的。
指纹怎么造,得按市场份额来
光改属性还不够,你改出来的指纹得「合理」。
什么叫合理?一个 Windows 用户配上 Apple M1 的 GPU,不合理。一个 macOS 用户配上 DirectX 渲染器,不合理。一台移动设备配 4K 桌面分辨率,也不合理。反 bot 系统专门找这种内部矛盾。
更要命的是,指纹的分布得符合真实世界的市场份额。
Camoufox 文档里举了个例子,假设 Linux 的真实市场份额是 5%,那如果你的 Agent 集群里有 20% 的请求伪装成 Linux,WAF(Web Application Firewall)的机器学习模型立刻就会发现异常,然后无差别地对所有 Linux 流量要求人机验证。
Camoufox 的解决方案是接入 BrowserForge 这个指纹生成器。BrowserForge 不是随机生成指纹,而是按照真实世界的统计分布来生成。比如 Linux 占 5%,那 Camoufox 生成的指纹里就只有 5% 是 Linux;在这 5% 里,2560x1440 分辨率占 9.5%,Intel HD GPU 占 27.5%,都严格按真实比例。
v149 之后的二进制还引入了一个更狠的特性,real fingerprint presets。它直接从真实 Firefox 流量里抓取指纹样本,打包成 312 个预设(67 个 macOS、180 个 Windows、65 个 Linux),用这些真实指纹作为模板。开启方式很简单:
with Camoufox(fingerprint_preset=True, os="macos") as browser:
...
UA 字符串会自动重写成匹配当前二进制版本的值,所以跨版本开启是安全的。
说真的,这种「按真实分布造指纹」的思路,比单纯「造一个看起来很真实的指纹」高了一个维度。前者解决的是单点合理性,后者解决的是群体统计特征。反 bot 系统的机器学习模型最擅长抓的就是统计异常。
把 Playwright 藏起来,Juggler 的妙用
光改指纹还不够,你的自动化工具本身也会暴露。
Playwright 控制 Chromium 用的是 CDP(Chrome DevTools Protocol),控制 Firefox 用的是 Juggler(Firefox 自己的自动化协议)。这两个协议在设计的时候就没考虑过隐藏自己。比如 navigator.webdriver 在 CDP 控制下会变成 true,再比如 CDP 会往页面注入一些内部变量用于通信。
Camoufox 选择 patch Juggler,而不是 CDP,这是一个很聪明的决定。原因在于,Juggler 是 Firefox 的一个独立模块,不是核心的一部分,改起来干净利落。
具体怎么做的呢?Camoufox 给 Playwright 分配了一个隔离的页面副本。Playwright 可以自由地读、写它自己那份页面,一切看起来都正常。但真实页面完全不受影响。页面也无法通过劫持 getter 之类的技巧探测到「有人在读我」。
更狠的是,Juggler 的输入会直接走 Firefox 原生的用户输入处理器。也就是说,Playwright 发出的点击、键盘事件,和真人用鼠标点出来的,走的是完全一样的代码路径。这一点对对抗那些监听输入事件特征的反 bot 系统非常关键。
还有一个细节,Camoufox patch 了 Firefox 的 headless 模式,让它在指纹层面和有头模式表现一致。万一哪天 headless 还是泄露了,Python 库还提供了 virtual display 作为兜底,直接在无头服务器上跑有头模式。
Python 接口,上手成本几乎为零
说了这么多底层,实际用起来是什么样?非常简单。
Camoufox 提供了同步和异步两套 API,完全兼容 Playwright 的接口。你只需要改一行初始化代码:
# 同步
from camoufox.sync_api import Camoufox
with Camoufox() as browser:
page = browser.new_page()
page.goto("https://example.com")
# 异步
from camoufox.async_api import AsyncCamoufox
async with AsyncCamoufox() as browser:
page = await browser.new_page()
await page.goto("https://example.com")
迁移成本就是改一个 import 和初始化语句,剩下的 Playwright 代码一行都不用动。这一点对已经在用 Playwright 的团队来说太友好了。
如果你需要硬件级的指纹隔离(per-context fingerprint),可以用 Clover Labs 维护的 cloverlabs-camoufox 包,API 和官方包完全一致:
pip install cloverlabs-camoufox
python -m camoufox sync
python -m camoufox set official/prerelease
python -m camoufox fetch
它能伪装什么
清单很长,我挑几个关键的列一下。
Navigator 属性全套,设备、OS、硬件、浏览器、语言、locale,都能改。网络层的 Accept-Languages 和 User-Agent 头会自动匹配 navigator 属性,不会出现 HTTP 头和 JS 不一致的情况。
WebRTC IP 在协议层伪装,不是靠禁用 WebRTC,而是真的把 IP 换掉。这点很重要,很多方案为了规避 WebRTC 泄露直接把它关了,反而成了一个特征。
屏幕、视口、分辨率全套,包括 inner 和 outer 窗口尺寸。
WebGL 全套,参数、扩展列表、上下文属性、shader 精度格式。
字体反指纹,会根据你伪装的 OS 自动加载对应的系统字体(打包了 Win、Mac、Linux 三套),还会随机偏移字母间距来对抗字体度量指纹。这个细节很讲究,因为字体度量是浏览器指纹里非常稳定的一个维度。
AudioContext,采样率、输出延迟、最大声道数都能伪装。
地理位置、时区、locale,这些会根据你的代理 IP 所在地区自动计算。你给它一个东京的代理,它自动把时区设成 Asia/Tokyo,locale 设成 ja-JP,不用你手动配。
电池 API、麦克风/摄像头/扬声器数量,这些冷门但会被检测的维度都覆盖了。
它不是银弹,作者自己也承认
文章写到这里,你可能会觉得 Camoufox 是反检测的终极方案。不是的。
作者在文档里有一段非常诚实的「2026 年现状说明」。原文大意是,由于个人原因,Camoufox 有一年左右的时间没人维护,基础 Firefox 版本落后了,指纹一致性也出现了一些新问题。目前正在积极开发中。
还有几个硬限制值得注意。
第一,它不能完全注入 Chromium 指纹。 有些 WAF(比如 Interstitial)会测试 SpiderMonkey 引擎的行为特征,这是 Firefox 的 JS 引擎,Chromium 用的是 V8,两者在底层行为上有差异,无法通过指纹伪装来弥合。如果你想伪装成 Chrome,Camoufox 帮不了你。
第二,指纹一致性是个无底洞。 几千个数据点,每一个改动都要和其他所有点保持一致。Camoufox 不能保证 100% 做到。反 bot 厂商会反复测试 Camoufox,找到一个独特的不一致点,然后立刻更新检测脚本。这是一个持续的攻防战。
第三,人类行为模拟还是 WIP。 Camoufox 内置了一个基于 HumanCursor 的鼠标轨迹算法,用 C++ 重写了,会根据距离调整轨迹。但作者自己也说,面对足够复杂的分析,这个算法还是可能被识别。未来还需要改进。
第四,构建系统只支持 Linux。 想自己 build Camoufox,得有 Linux 环境,WSL 也不行。好在官方提供了 Docker 方案。
这些诚实的声明反而让我更信任这个项目。一个会主动告诉你「哪里不行」的工具,比一个号称「百分百过检」的工具靠谱得多。后者要么在骗你,要么很快会被反 bot 厂商针对性击穿。
一些有意思的工程细节
翻代码的过程中,还有几个细节让我觉得这个项目做得比较扎实。
它真的 debloat 了。 大量 Mozilla 服务被砍掉,集成了 LibreWolf、Ghostery、PeskyFox、FastFox 的去遥测和优化 patch。内存占用压到 200MB 左右,比原版 Firefox 还快。CSS 动画全部移除,主题极简化。一个反检测浏览器做成这样,说明作者没把它当玩具。
自带 uBlock Origin。 而且带了自定义隐私 filter,修复了 uBO prefetch 导致的 DNS 泄露。插件在隐私浏览模式自动启用,自动 pin 到工具栏,不允许开新标签页。这些细节都是踩过坑才会想到的。
远程服务器托管。 Python 库支持把 Camoufox 部署在远程服务器上,这样其他支持 Playwright 的语言也能用。对 Go、Rust、Node.js 的爬虫团队很友好。
内置虚拟显示。 无头服务器上跑有头模式不用再折腾 Xvfb,库自己搞定。
一个完整的 leak 调试流程。 文档里有一个流程图,教你如何在不反混淆 WAF JavaScript 的前提下定位泄露点。思路是逐步把 Camoufox 的特性重新引入 Firefox 源码,直到测试站点开始拦截。这套方法论对贡献者维护 patch 非常有价值。
写在最后
Camoufox 给我的最大启发不是它的反检测技术有多强,而是它的工程哲学。
面对一个猫鼠游戏式的问题,它没有选择在对手的领地里玩游戏(JS 注入),而是直接换了一个对手够不到的层级(C++ 源码)。面对指纹合理性问题,它没有选择「造一个完美的假指纹」,而是「按真实世界的分布批量造假」,从统计层面融入正常流量。
这种思路不仅适用于反检测,对所有做自动化的同学都有借鉴意义。当你发现一个问题在某一层怎么都解决不干净的时候,问问自己,是不是该换个层级了。
如果你在做 AI Agent 的数据采集层,或者在做需要大规模并发的爬虫,Camoufox 值得一试。它的 Python 接口让你几乎零成本接入,C++ 层的伪装让你不用再和 JS stealth 插件较劲,BrowserForge 的市场份额指纹让你的 Agent 集群不那么显眼。
当然,别忘了它还在积极开发中。如果你的场景对稳定性要求极高,建议先在小流量上验证。如果你愿意为开源项目贡献,这个项目目前正是需要人的时候。
最后一句提醒,Camoufox 的设计前提是配合住宅代理使用。再好的指纹伪装,配一个数据中心 IP,还是会被很多站点直接拦掉。工具是工具,配套的基础设施一样不能少。
评论互动