news 2026/2/28 0:06:05

前端指纹技术是如何实现的?(Canvas、Audio、硬件API 核心原理解密)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端指纹技术是如何实现的?(Canvas、Audio、硬件API 核心原理解密)

什么是设备指纹?

在讲实现之前,先纠正一个误区:设备指纹(Device Fingerprint)不是为了知道你是张三,而是为了知道这台设备是编号 9527

它的核心逻辑只有一条:利用浏览器暴露的硬件底层差异(显卡、声卡、电池、屏幕),组合出极高熵值的唯一 ID。

就算你清空了 Cookie,换了 IP,只要你的硬件没变,这套代码算出来的 Hash 值就永远不变。

下面我们直接上代码,拆解最核心的三种实现方式。

Canvas 指纹

这是目前最成熟、识别率最高的技术。

实现原理

Canvas 绘图不仅仅依赖浏览器引擎,它极度依赖底层的GPU 绘图指令操作系统图形驱动以及抗锯齿(Anti-aliasing)算法

当你命令浏览器画一个红色的矩形,里面写上 Hello, world!时:

  • NVIDIA 的显卡和 AMD 的显卡,在处理边缘像素的混合(抗锯齿)时,算法有微小的数学差异。
  • Windows 和 Mac 在字体渲染(Sub-pixel rendering)上,对笔画粗细的处理不同。
  • 这就导致了:同一段 Canvas 代码,生成的图片像素数据(RGBA),在不同设备上是完全不同的。

核心代码实现方式

我们不需要画多复杂的图,关键是要触发差异。通常会用到:光影叠加、异形字体、emoji(检测字体库)。

function getCanvasFingerprint() { // 1. 创建一个不会挂载到 DOM 上的画布 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 200; canvas.height = 50; // 2. 文字干扰:利用字体渲染差异 // textBaseline 设为 top/bottom 会触发不同的垂直对齐算法 ctx.textBaseline = "top"; ctx.font = "14px 'Arial'"; ctx.fillStyle = "#f60"; ctx.fillRect(125, 1, 62, 20); // 背景块 // 3. 叠加混合:触发 GPU 的颜色混合算法 ctx.fillStyle = "#069"; // 写入带特殊符号的文字,测试系统字体支持度 ctx.fillText("Hello, world! \ud83d\ude03", 2, 15); // 再次叠加,利用 rgba 透明度触发抗锯齿差异 ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; ctx.fillText("Hello, world! \ud83d\ude03", 4, 17); // 4. 导出指纹 // toDataURL 会返回 base64 字符串 // 同样的图像,不同显卡生成的 base64 字符串的 CRC 校验码是不同的 const b64 = canvas.toDataURL().replace("data:image/png;base64,", ""); // 5. 将超长字符串 Hash 化 (这里用简单的 hash 示例,生产环境可用 MurmurHash3) let bin = atob(b64); let crc = bin2hex(bin.slice(-16, -12)); // 取部分校验位 return crc; }

差异在哪?

肉眼看这两张图是一模一样的。

但如果你把两台电脑生成的 Base64 字符串拿去对比,会发现可能在第 5000 个字符处,有一个字母不一样。那就是显卡留下的签名。

AudioContext 指纹

既然显卡有差异,声卡(Audio Stack)自然也有。

原理


Audio 指纹不是录音(不需要麦克风权限)。

它是利用 Web Audio API
生成一段数学上的声音信号(正弦波、三角波),然后经过一系列处理(压缩、滤波)。

由于计算机浮点数运算的精度差异,以及底层音频处理单元(DSP)的实现不同,最终生成的PCM 音频数据流会有极其微小的差别。

代码实现

通常使用OfflineAudioContext(离线音频上下文),它可以在后台静默渲染音频,不需要用户听到声音,速度极快。

function getAudioFingerprint() { // 兼容性处理 const AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext; if (!AudioContext) return null; // 1. 创建离线上下文:1个声道,44100采样率,5000帧 const context = new AudioContext(1, 5000, 44100); // 2. 创建振荡器 (Oscillator) // 三角波 (triangle) 比正弦波更容易暴露硬件处理的非线性差异 const oscillator = context.createOscillator(); oscillator.type = 'triangle'; oscillator.frequency.value = 10000; // 3. 创建动态压缩器 (Compressor) - 核心步骤 // 压缩器的算法在不同浏览器/硬件上实现差异很大 const compressor = context.createDynamicsCompressor(); compressor.threshold.value = -50; compressor.knee.value = 40; compressor.ratio.value = 12; compressor.reduction.value = -20; // 4. 连接节点:振荡器 -> 压缩器 -> 输出 oscillator.connect(compressor); compressor.connect(context.destination); // 5. 开始渲染 oscillator.start(0); context.startRendering().then(buffer => { // 6. 获取渲染后的 PCM 数据 // 这是一个 Float32Array 数组 const data = buffer.getChannelData(0); // 7. 计算 Hash let sum = 0; // 简单累加所有采样点的绝对值,作为指纹 for (let i = 0; i < data.length; i++) { sum += Math.abs(data[i]); } console.log("Audio Fingerprint:", sum); }); }

不同设备跑出来的sum值,会精确到小数点后十几位,那个微小的尾数差异就是指纹。

电池与硬件并发

光有 Canvas 和 Audio 还不够(因为同一型号的 iPhone 可能会完全一样)。这时候需要引入动态硬件特征来增加熵值。

电池电量 API (Battery Status API)

注:由于隐私争议太大,Firefox 和 Safari 已禁用,但 Chrome (部分版本) 和 Android Webview 中依然可能获取。

这玩意的逻辑非常粗暴:

电量百分比, 充电/放电时间这个组合在特定时间点是极具唯一性的。

// 核心代码 navigator.getBattery().then(battery => { const level = battery.level; // 例如 0.55 const chargingTime = battery.chargingTime; // 例如 1200 (秒) const dischargingTime = battery.dischargingTime; // 例如 Infinity // 指纹因子:0.55_1200_Infinity // 结合 IP,能把用户锁定得死死的 const batteryFingerprint = `${level}_${chargingTime}_${dischargingTime}`; });

如果我在 1 分钟内连续请求两次,发现你的电量从0.42变成了0.41,这个变化曲线也是一种强指纹。

硬件并发数与内存

这些是Navigator对象上赤裸裸的硬件参数:

const hardwareInfo = [ navigator.hardwareConcurrency, // CPU 核心数,如 12 navigator.deviceMemory, // 内存大小 (GB),如 8 screen.width + 'x' + screen.height, // 分辨率 screen.colorDepth, // 色彩深度,如 24 window.devicePixelRatio // 像素比,如 2 ].join('_'); // 输出示例:12_8_2560x1440_24_2

虽然这些参数单看很普通,但如果你把CPU + 内存 + 分辨率 + Canvas指纹 + Audio指纹拼接在一起,全球几十亿设备中,能和你撞车的概率,几乎为零。

所谓的前端指纹技术,本质上就是找不同的一种方式。

开发者利用一切可以调用的 API(Canvas, Audio, WebGL, 硬件信息),强迫浏览器进行某种复杂的运算。由于硬件和驱动的细微差别,运算结果必然存在差异。

这些差异被收集起来,生成了一个字符串。

这就是浏览器在互联网上的唯一ID,希望对你们有帮助。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/26 21:33:21

收藏!大模型技术与应用体系梳理(小白程序员入门必看)

大模型技术开发属于多学科交叉的复杂领域&#xff0c;对初学者而言&#xff0c;搭建一套清晰的基础认知体系是关键——唯有理清核心逻辑&#xff0c;才能明确学习方向、掌握实操路径&#xff0c;避免在繁杂概念中迷失。 随着大模型技术的普及&#xff0c;笔者在与同行、技术爱好…

作者头像 李华
网站建设 2026/2/26 3:18:49

别管,咱们前端人有自己的拼夕夕~

这份清单&#xff0c;是无数次面试复盘后沉淀下来的“考点最大公约数”&#xff0c;是八股文里的精华。它由十六个经典模块构成&#xff0c;像积木一样&#xff0c;能拼出绝大多数大厂面试的轮廓&#xff1a; 1.JavaScript 深度解剖室&#xff1a;这里不问“怎么用”&#xff…

作者头像 李华
网站建设 2026/2/26 21:28:15

强烈安利10个一键生成论文工具,继续教育学生轻松搞定论文!

强烈安利10个一键生成论文工具&#xff0c;继续教育学生轻松搞定论文&#xff01; AI 工具如何助力论文写作&#xff1f; 在当今信息爆炸的时代&#xff0c;继续教育学生面对的论文写作任务日益繁重。传统的写作方式不仅耗时费力&#xff0c;还容易因思路不清晰或资料不足而陷入…

作者头像 李华
网站建设 2026/2/25 20:57:31

基于OpenPLC的产线控制实战案例详解

用树莓派OpenPLC重构产线控制&#xff1a;一个工业自动化工程师的实战手记最近接手了一个老产线升级项目&#xff0c;客户原用的是三菱FX3U PLC&#xff0c;配了个触摸屏&#xff0c;运行了快八年。系统稳定但扩展性极差——想加两个传感器&#xff1f;得换PLC模块、改接线、重…

作者头像 李华
网站建设 2026/2/27 7:46:06

从巨额亏损中提炼出的3条颠覆性交易心法

引言&#xff1a;你是否也在用“猜谜”的方式炒股&#xff1f;你是否也曾在股市的海洋中感到迷茫&#xff1f;每天被海量的信息淹没&#xff0c;反复追涨杀跌&#xff0c;最终却发现账户数字不增反减。我们总想找到那个能够精准预测市场的“水晶球”&#xff0c;但现实往往是&a…

作者头像 李华
网站建设 2026/2/25 5:56:18

电影解说详细教程:从「一条视频」到「持续更新」

很多人第一次做电影解说&#xff0c;都会经历一个相似的过程&#xff1a;第一条视频做得很认真&#xff0c;从选片到剪辑反复打磨&#xff0c;虽然播放量未必高&#xff0c;但至少“做出来了”。可问题也往往从这里开始——第二条、第三条迟迟没动静&#xff0c;更新开始断断续…

作者头像 李华