在 Web 设备识别场景中,一个常见的问题是:浏览器能否直接读取设备的 MAC 地址?
答案是不能。MAC 地址属于数据链路层标识,而浏览器运行在应用层,中间隔着操作系统内核和网络协议栈。出于隐私和安全考虑,主流浏览器均不允许网页直接访问网卡 MAC 地址。WebRTC 偶尔能够暴露局域网 IP,但并不能获取 MAC。Java Applet、ActiveX 等旧技术也早已退出主流 Web 开发。
既然无法获取硬件唯一标识,现代 Web 通常采用设备指纹(Device Fingerprinting)方案:采集浏览器、操作系统和硬件环境的多个特征,组合计算出一个相对稳定的设备标识。
一、设备指纹采集哪些信息?
常见的指纹信号可以分为几类:
- 图形与音频特征:Canvas、WebGL、AudioContext。不同设备的 GPU、驱动和渲染实现存在差异,可以产生具有一定区分度的结果。
- 浏览器环境:User-Agent、语言、时区、平台、屏幕分辨率、字体列表等。
- 硬件信息:CPU 逻辑核心数(hardwareConcurrency)、设备内存(deviceMemory)等。
- 持久化标识:在 localStorage 中写入随机 UUID,作为设备识别的辅助依据。
- 网络信息:IP 地址可以辅助判断设备环境,但会随着网络切换而变化,不适合作为主要设备标识。
单一特征通常不够可靠,真正有效的是将多个特征组合起来,经过归一化和哈希处理,形成设备指纹。
二、有哪些开源实现?
前端设备指纹并不需要从零开发,可以直接使用现有 JavaScript 库:
| 项目 | 许可证 | 特点 |
|---|---|---|
| ThumbmarkJS | MIT | 轻量级浏览器指纹库 |
| FingerprintJS | 版本相关 | 成熟的指纹采集方案 |
| ClientJS | Apache-2.0 | 传统指纹库,维护较少 |
| CreepJS | MIT | 偏研究用途,关注浏览器特征与反指纹检测 |
需要特别注意 FingerprintJS 的许可证变化:v3/v5+ 使用 MIT,v4.x 使用 BUSL-1.1。BUSL 并非传统意义上的开源许可证,商业使用前应核实具体版本及授权条件。
三、生产环境如何设计?
纯前端指纹存在一个明显问题:采集过程运行在用户控制的浏览器中,攻击者可以通过 Hook JavaScript API、修改返回值等方式伪造采集结果。
因此,生产环境不应直接把前端生成的指纹哈希当作可信设备 ID。更合理的架构是:
- 前端采集 Canvas、WebGL、AudioContext 等环境特征。
- 将必要的原始特征或其摘要提交服务端。
- 服务端统一计算指纹,并进行一致性和异常校验。
- 结合 localStorage UUID、登录账号、历史行为等信息进行综合判定。
需要强调的是,设备指纹本质上是一种概率性识别技术,而不是硬件身份认证机制。它适合风险控制、异常登录检测和设备关联,不应该单独承担身份认证职责。
四、为什么不应该使用 Evercookie?
还有一种追求极端持久性的方案叫 Evercookie,也被称为 Zombie Cookie(僵尸 Cookie)。
它会将同一个标识写入 Cookie、localStorage、IndexedDB、ETag、缓存图片等多个存储位置。当用户清除其中一部分数据时,再从其他位置恢复标识。
这种设计虽然提高了追踪持久性,却直接对抗用户清除数据的意图。它在欧盟 ePrivacy/GDPR 和国内《个人信息保护法》框架下都存在较高合规风险。现代浏览器也在持续限制第三方存储和跨站追踪能力。
因此,不建议在生产环境中采用 Evercookie。
五、在稳定性与隐私之间取得平衡
比较合理的方案是:使用 Canvas、WebGL、AudioContext、字体等特征生成设备指纹,同时通过 localStorage 保存一个允许用户主动清除的随机 UUID。服务端再结合指纹、UUID 和登录状态进行综合判断。
对于设备指纹,还应在隐私政策中明确说明采集范围、处理目的和使用方式,并根据适用法律要求取得必要授权,提供相应的查询、删除或撤回机制。
设备识别的目标不是实现永远无法删除的唯一标识,而是在业务需要、识别准确性和用户隐私之间取得平衡。 这才是能够长期运行的 Web 设备指纹方案。