← 返回博客
Browser window with code brackets, a data-point fingerprint and a privacy shield
操作指南

如何用 JavaScript 获取浏览器指纹:代码示例、局限与隐私规则

Kenji Watanabe Kenji Watanabe 发布于 2026年9月26日 · 分类操作指南

用 JavaScript 获取浏览器指纹,做法是读取浏览器公开的一组属性(User-Agent、语言、时区、屏幕尺寸、硬件信息),再加上 Canvas 绘图这类渲染测试,把这些值拼成一个字符串,用 Web Crypto API 算出哈希。得到的是一个概率性的标识,并不是稳定的 ID;在欧盟,采集它通常需要征得用户同意。

本文用原生 JavaScript 把这个过程走一遍,讲清为什么结果变化得比想象中频繁,并说明相关的隐私规则。适合想了解自己浏览器会暴露什么信息的开发者,也适合做风控和账号安全功能的团队。各类指纹技术的完整介绍,见我们的浏览器指纹技术详解。

什么是浏览器指纹

W3C 关于减少浏览器指纹的指导文件,把浏览器指纹定义为:网站通过配置设置或其他可观察特征,识别或再次识别访问用户、用户代理或设备的能力。文件把它分为两类:

  • 被动指纹:只用每次请求自带的信息,例如 HTTP 请求头和 IP 地址,不需要在设备上运行代码。
  • 主动指纹:在设备上运行 JavaScript 等代码,观察更多特征,例如字体、窗口大小或设备传感器。

本文讲的都是主动指纹:页面向浏览器提问,并记录回答。MDN 术语表列出的典型组成包括:浏览器版本、时区和首选语言、可用的音视频编解码器、已安装字体、浏览器设置状态,以及屏幕尺寸和分辨率。

第一步:采集基础属性

大部分属性来自标准对象,不会弹出任何权限提示:

function collectAttributes() {
  return {
    userAgent: navigator.userAgent,
    languages: (navigator.languages || []).join(','),
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    screen: [screen.width, screen.height, screen.colorDepth].join('x'),
    pixelRatio: window.devicePixelRatio,
    cores: navigator.hardwareConcurrency || null,
    memory: navigator.deviceMemory || null,
    touchPoints: navigator.maxTouchPoints || 0
  };
}

有两点要注意。navigator.deviceMemory 只在基于 Chromium 的浏览器里提供,其他浏览器返回 undefined,所以代码里存成 null。另外,Chromium 系浏览器已经精简了默认的 User-Agent 字符串,把细节移到了 User-Agent Client Hints 里,单看 User-Agent 能拿到的信息比以前少。

第二步:加入 Canvas 渲染测试

区分度主要来自渲染测试。页面在一块不显示的画布上绘制文字和图形,再把结果读回来。不同机器在字体渲染、抗锯齿和图形硬件上有细微差别,输出也就不同:

function canvasSignal() {
  const canvas = document.createElement('canvas');
  canvas.width = 240;
  canvas.height = 60;
  const ctx = canvas.getContext('2d');
  if (!ctx) return 'no-canvas';
  ctx.textBaseline = 'top';
  ctx.font = '16px Arial';
  ctx.fillStyle = '#f60';
  ctx.fillRect(100, 1, 62, 20);
  ctx.fillStyle = '#069';
  ctx.fillText('fingerprint test 123', 2, 15);
  return canvas.toDataURL();
}

这块画布不会加到页面上,访客看不到任何东西。WebGL 和音频处理也有类似的测试,套路相同:渲染、读回、算哈希。

第三步:合并并计算哈希

Canvas 输出的 data URL 很长,所以最后一步通常是把所有值哈希成一个短值。Web Crypto API 的 crypto.subtle.digest 支持 SHA-256。据 MDN 说明,它只能在安全上下文中使用,也就是通过 HTTPS 或 localhost 访问的页面:

async function sha256Hex(text) {
  const bytes = new TextEncoder().encode(text);
  const hash = await crypto.subtle.digest('SHA-256', bytes);
  return Array.from(new Uint8Array(hash))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

async function getFingerprint() {
  const data = collectAttributes();
  data.canvas = canvasSignal();
  const keys = Object.keys(data).sort();
  const text = keys.map(k => k + '=' + data[k]).join('|');
  return sha256Hex(text);
}

getFingerprint().then(id => console.log('fingerprint', id));

对字段名排序,是为了让拼接顺序每次一致,相同的输入总能得到相同的哈希。

为什么指纹总在变

实际跑一下就会发现,这个哈希没有想象中稳定。常见原因有:

  • 浏览器更新会改变 User-Agent 字符串,有时也会改变渲染结果,一次更新就可能产生新的哈希。
  • 屏幕和窗口变化,例如接了外接显示器或调整了缩放比例,屏幕和像素比的值随之改变。
  • 浏览器的主动防护。 各家浏览器都在限制指纹采集。Brave 会给 Canvas、WebGL 和音频结果加入细微的随机化,让同一个浏览器在不同网站、不同会话之间看起来都不一样;Firefox 和 Safari 会限制或模糊化脚本能读到的信息;Tor 浏览器则尽量让所有用户看起来一样。
  • 隐私窗口或嵌入式环境中,部分 API 受限或返回默认值。

所以单独一个完整哈希并不适合当标识。生产环境里的系统一般会逐项比对信号、接受部分匹配,再结合其他证据综合判断。为什么各项数值之间的一致性比「独一无二」更重要,可以参考我们的浏览器指纹检测结果怎么看。

隐私与法律规则

W3C 的指导文件指出了指纹敏感的原因:和 Cookie 不同,浏览器指纹通常无法被用户清除或重置,即使用户主动删除了 Cookie,也可能被再次识别。

在欧盟,欧洲数据保护委员会(EDPB)发布的《关于电子隐私指令第 5(3) 条技术适用范围的第 2/2023 号指南》(最终版于 2024 年 10 月通过)明确,关于访问用户设备中信息的规定不只适用于 Cookie,也可以适用于设备指纹技术。实际做法是:除非处理对用户主动请求的服务确属必要,否则要先征得同意。涉及个人数据时,还要同时遵守 GDPR。在生产环境采集指纹之前,请先和法务确认适用规则。

在风控、账号安全这类正当用途中,建议做到:

  • 只采集必要的信号,并在隐私政策中写明。
  • 保存哈希而不是原始值,并设定保存期限。
  • 不用指纹在互不相关的网站之间追踪用户。

对广告运营意味着什么

广告平台在自己的页面上也会读取很多同样的信号,这是投放团队关心指纹的原因。理解这些信号,有助于把本来就应当分开的环境(例如不同客户、不同团队成员)配置得一致、规范。但它不是绕开平台规则的手段:Meta、Google、TikTok 都禁止任何规避审核或执法的做法,任何指纹配置都改变不了这一点。

常见问题

JavaScript 能拿到唯一的浏览器 ID 吗?

不能可靠地拿到。JavaScript 可以把属性和渲染测试合成一个往往很有区分度的哈希,但浏览器更新、显示设置变化和内置防护都会让它随时间改变,只能当作概率性信号。

采集浏览器指纹需要用户同意吗?

在欧盟通常需要。EDPB 第 2/2023 号指南说明,电子隐私指令第 5(3) 条可以适用于设备指纹,除非处理对用户请求的服务确属必要,否则需要征得同意。

为什么页面上 crypto.subtle 用不了?

crypto.subtle 只能在安全上下文中使用。请通过 HTTPS 提供页面,或在 localhost 上测试。

浏览器能拦截指纹脚本吗?

浏览器会减少脚本能获取的信息。Brave 会随机化 Canvas、WebGL 和音频输出,Firefox 和 Safari 会限制部分 API,Tor 浏览器则把大量数值统一,让用户看起来彼此相同。

了解适合团队的配置方案

与商务团队沟通账号、IP 和环境需求,确认配置与交付方式。

联系商务