FingerprintJS 是开源库,与付费产品 Fingerprint 不同:它采集什么、准确度多高,以及与 CreepJS 有何区别。
搜索「fingerprintjs」,结果里常常混着两样不同的东西。一个是开源 JavaScript 库,任何网页都能免费引入:它完全在访客的浏览器里运行,返回一个 visitorId 字符串。另一个是 Fingerprint,同一家公司出售的付费商业识别服务,额外加入了服务端处理,宣称的准确率也高得多。两者名字相同、同属一个 GitHub 组织,思路也大体一致——把大量浏览器信号合成一个标识符——除此之外并没有太多共同点。本文讲的是前者:这个开源库实际读取哪些信号、如何把它们变成 visitorId、真实准确度如何,以及它和本站介绍过的其他指纹检测工具相比处于什么位置。
核心要点
- 免费、采用 MIT 许可证的 FingerprintJS 库,和付费产品 Fingerprint 出自同一家公司,但并非同一样东西。开源库完全在客户端运行,它的 README 自己也写明,准确度比商业版「低得多」。
- 这个库读取约 40 项浏览器信号——Canvas 绘制、已安装字体、音频处理、WebGL 渲染器信息、屏幕与硬件属性、时区与语言、显示偏好等——并把它们哈希成一个
visitorId。 visitorId回答的是*「这是不是上次那个浏览器?」,属于稳定性问题;CreepJS 问的是「这个浏览器有没有谎报自己?」,Cover Your Tracks 问的是「这个组合有多罕见?」*,三者并不相同。- 由于不依赖 Cookie 或本地存储,这种指纹在无痕模式下、清除浏览数据之后依然不变;但底层信号一旦变化——比如浏览器或显卡驱动更新,或者浏览器会刻意随机化指纹特征——它也会跟着变。
- README 没有给出开源库的准确率百分比,本文也不给。看到有人为它引用具体数字时,请保持谨慎。
两个都叫「FingerprintJS」的东西
这种混淆源自项目本身的历史。FingerprintJS Inc. 最初做的就是这个开源库,后来基于同一思路推出了商业产品,如今公司以 Fingerprint 为名运营。开源库仍在维护,npm install @fingerprintjs/fingerprintjs 装到的就是它——但公司的大部分宣传,以及许多第三方关于「FingerprintJS」的文章,描述的其实是付费产品才有、免费库并不具备的能力。
评估两者时,真正要紧的差异有三点:
- 运行位置。 开源库在访客浏览器内完成全部计算,把
visitorId交给网页。商业产品还会在厂商服务器上处理每次请求,能用上网页脚本自己拿不到的信号(例如连接的 IP 地址),并与以往的访问记录进行比对。 - 费用。 开源库以 MIT 许可证免费提供;商业产品是按用量计费的付费 API。
- 各自的说法。 README 明确写道:由于指纹是在浏览器内生成的,开源库的准确度比商业版低得多。厂商之所以为付费产品宣传高得多的准确率,靠的正是那层服务端处理。
如果你搜索「fingerprintjs」是想找一个能自己部署的免费库,开源项目就是它。如果你在为企业评估反欺诈或反机器人方案,你真正在看的是商业产品——两者不该被当成「同一个工具换了个品牌」来比较。
开源库实际读取什么
抛开品牌不谈,这个库用的技术和本站其他文章讲过的属于同一类:一组固定的客户端信号,采集后哈希成一个值。它的源码把每项信号定义为一个「熵源」(entropy source),当前版本约有 40 个。按类型归纳如下:
- Canvas 绘制。 即《Canvas 指纹检测:网站如何识别你的设备》介绍的隐藏绘制技术:同样的文字和图形,会因 GPU、驱动和字体渲染不同而出现细微的像素差异,无需 Cookie 就能得到稳定的哈希。
- WebGL。 基础 WebGL 参数,如上报的厂商(vendor)与渲染器(renderer)字符串,以及支持的 WebGL 扩展列表。
- 音频。 通过 Web Audio API 处理一小段信号(机制见《音频指纹:AudioContext 如何识别你的设备》),同时读取音频栈上报的基础延迟。差异来自音频实现和硬件,而不是用户能调整的任何设置。
- 字体。 安装了哪些字体,以及默认字体族的实际渲染效果,二者都随操作系统、语言包和已装软件而不同。
- 屏幕与硬件。 屏幕分辨率与色深、操作系统在可用屏幕区域周围占用的空间(如任务栏或程序坞)、CPU 核心数(
hardwareConcurrency)、设备内存的粗略值,以及是否支持触控。 - 区域设置。 时区、首选语言,以及日期时间格式所用的区域设置。
- 平台与浏览器。 上报的平台与 CPU 架构、浏览器厂商、已安装插件、是否启用内置 PDF 查看器,以及 Apple Pay 可用性等少数引擎特有的检查。
- 偏好与环境。 色域、强制颜色或反色、对比度与减少动态效果偏好、HDR 支持等 CSS 媒体特性;Cookie 与各类存储 API 是否可用;似乎启用了哪些内容拦截器;以及
Math函数的细微浮点差异。
这些信号没有一项是 FingerprintJS 独有的——《浏览器指纹详解:如何保护你的隐私》从更通用的角度讲过这些底层技术。这个库的价值在于打包:一段持续维护的脚本,把整套信号采集齐全并转成一个字符串,网站不必自己编写采集逻辑。
从信号到 visitorId
调用库的 get() 方法会返回四样东西:visitorId;表示库对该标识符有多大把握的 confidence(置信度)分数;采集到的原始 components;以及指纹算法的 version。visitorId 本身是把所有信号序列化成一个字符串后,再用 128 位哈希(库中的 x64hash128 函数,MurmurHash3 的一个变体)算出的结果。任何一项信号变了,哈希值就会完全不同——不存在「差不多一样」的 visitorId。
它到底有多准确
README 里有两个说法值得分开看。第一,指纹不依赖 Cookie 或本地存储,因此「在无痕/隐私模式下,甚至清除浏览器数据之后,依然保持不变」。这正是网站使用指纹识别的根本原因:清 Cookie 重置不了它。
第二,README 表示,由于 FingerprintJS 在浏览器内生成指纹,其准确度比商业版低得多。它没有公布具体百分比,本文也不会给出。
为什么会更低?从 visitorId 的构造方式可以直接推出两个结构性原因——以下是我们的分析,并非该项目的说法:
- 漂移。 哈希覆盖所有信号,任何一项变化都会产生新的
visitorId。浏览器更新可能改变 Canvas 上的文字渲染;显卡驱动更新可能改变 Canvas 输出或 WebGL 渲染器字符串;新装一款字体会改变字体列表;带有反指纹保护、会刻意给 Canvas 或音频输出加噪的浏览器,可能在不同会话或不同网站之间返回不同的值。信号变了的回访者,看起来就像一个全新的访客。 - 碰撞。 反过来的问题:型号、系统版本和浏览器版本都相同的设备——比如一批配置完全一致的办公笔记本,或两台运行同一 iOS 版本的同型号 iPhone——可能暴露几乎一样的信号,算出同一个
visitorId,让不同的人看起来像同一个访客。
纯浏览器脚本自己无法纠正这两类错误。服务端系统则可以参考更多证据,比如访问来自哪个网络、以往的访问记录——这正是商业产品要填补的空白。
FingerprintJS 在这些检测工具中的位置
FingerprintJS 的 visitorId 只回答一个具体问题:这是不是之前来过的那个浏览器? 这是稳定性问题。有必要说清它和本站介绍过的其他工具有何不同,因为同一个浏览器,换一个问题来问,就可能得到三种听起来截然不同的结论:
- CreepJS 问的是这个浏览器有没有如实描述自己?——一种一致性检查,交叉比对可信与不可信的信号来源,寻找内部矛盾。按 CreepJS 的标准毫无破绽的浏览器,照样可能产生一个高度稳定、极易被追踪的
visitorId。 - Cover Your Tracks 问的是这组信号组合有多罕见?——用信息论来回答的唯一性问题,和信号是否自洽、跨会话是否稳定都无关。
- FingerprintJS 两个都不问。它问的是:同一组信号按同样方式哈希,能否再次得到同一个标识符——这是可重复性问题,既说明不了这组组合有多常见,也判断不了某项信号是否被篡改过。
《指纹检测工具为何对你各执一词》对这一规律做了系统梳理:唯一性、一致性与身份稳定性是三种不同的度量,却常被笼统地称作「分数」或「ID」;为其中一种设计的工具,本来就没打算回答另外两种。如果你拿 visitorId 这类结果去对照 CreepJS 的信任分或 Cover Your Tracks 的匿名度数值,发现对不上,这很正常——它们回答的根本不是同一个问题。《BrowserLeaks 详解:每项测试到底检测什么泄露》则补上了这类工具的第四种形态:逐项分别报告每个检测面、完全不汇总成单一数字的测试集。
检查你自己的信号
BrowserInsight 的指纹检测展示了这个库读取的许多同类信号——Canvas、WebGL、音频、字体、屏幕和 navigator 属性——逐项列出,并配有一致性检查,在信号相互矛盾时给出提示。它不会再算一个与之对标的 visitorId,而是把指纹库会拿去哈希的原始信号摆在你面前,让你看清是哪几项让你的浏览器与众不同。想亲眼看看漂移:先跑一次检测,然后更新浏览器,或开启浏览器自带的防指纹功能(如果有),再跑一次——发生变化的 Canvas、WebGL 或字体数值,正是会让 FingerprintJS 生成新 visitorId 的那类变化。
常见问题
开源的 FingerprintJS 库和 Fingerprint 产品是同一个东西吗?
不是。两者出自同一家公司,都基于哈希思路,但开源库完全在客户端运行,其 README 也写明准确度比商业版低得多;付费的 Fingerprint 产品则加入了免费库没有的服务端处理。
开源库可以用在商业网站上吗?
该库以 MIT 许可证发布,这一许可证允许商业使用。具体条款请以仓库中的许可证文件为准。
FingerprintJS 会收集或存储关于我的数据吗?
开源库本身只是一段在你浏览器里运行、返回 visitorId 的脚本;这个标识符之后是否被存储、存在哪里,完全取决于部署它的网站,而不是库本身。请查看具体网站的隐私政策,不要想当然地猜测指纹脚本的输出会被如何处理。
为什么我的 visitorId 在两次访问之间变了?
因为它是库读取的全部信号的哈希,任何一项变化都会得到不同的 ID。常见原因包括浏览器更新、显卡驱动更新、新装字体,以及会随机化 Canvas 或音频输出的反指纹功能。相反,打开无痕窗口或清除 Cookie 按理不会改变它——README 称这两种情况下指纹都保持不变。
FingerprintJS 比 CreepJS 或 Cover Your Tracks 更准确吗?
这个比较本身不太成立,因为三个工具测的不是同一件事。FingerprintJS 问同一个访客能否两次得到同一个标识符;CreepJS 问浏览器的信号是否内部一致;Cover Your Tracks 问这个组合有多罕见。只有两个工具想回答同一个问题时,「更准确」才有意义。


