+
7
-

回答

浏览器指纹(Browser Fingerprinting)是一种在不使用Cookie等技术的情况下,通过收集设备硬件和软件的独特特征来识别用户的技术。

它的核心原理在于,即便是细微的硬件或软件差异,也会导致浏览器在执行特定任务(如图形、音频渲染)时产生完全不同的输出结果,从而生成一个高熵值的唯一标识符。

以下是实现这三种主流指纹技术的详细JavaScript方法。

1. Canvas指纹

Canvas指纹是目前最成熟、识别率最高的技术。它利用不同设备在GPU、显卡驱动、操作系统及浏览器渲染引擎上的差异来提取指纹。

实现原理:脚本会在后台创建隐藏的画布,通过组合绘制文字、几何图形、阴影和渐变等指令,最大程度地触发系统底层的渲染差异。

核心代码

function getCanvasFingerprint() {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = 200;
  canvas.height = 50;

  // 1. 设置文字样式,触发不同平台的字体渲染差异
  ctx.textBaseline = "top";
  ctx.font = "14px 'Arial'";
  ctx.fillStyle = "#f60";
  ctx.fillRect(125, 1, 62, 20);

  // 2. 绘制带特殊符号和透明度的文字,触发GPU的颜色混合与抗锯齿算法
  ctx.fillStyle = "#069";
  ctx.fillText("Hello, world! ", 2, 15); // 特殊符号(Emoji)检测字体库
  ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; // 透明度触发抗锯齿差异
  ctx.fillText("Hello, world! ", 4, 17);

  // 3. 导出为Base64字符串,不同设备/浏览器生成的字符串会有差异
  const base64 = canvas.toDataURL().replace("data:image/png;base64,", "");

  // 4. 将字符串哈希化,生成最终的指纹
  // 注意:这里仅为示例,生产环境中建议使用更健壮的哈希算法,如SHA-256
  let hash = 0;
  for (let i = 0; i < base64.length; i++) {
    const char = base64.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash |= 0; // Convert to 32bit integer
  }
  return hash.toString();
}

工作原理:虽然肉眼看到的图形可能完全相同,但将Base64字符串哈希后,你会发现不同设备生成的哈希值有微小差异,这就是显卡和渲染器留下的独特“签名”。为了获得更可靠的指纹,通常会使用SHA-256等加密哈希函数来处理导出的图片数据。

2. AudioContext指纹

AudioContext指纹利用的是不同设备在音频信号处理上的细微差别,主要源于硬件(DSP)、软件(音频栈)和浏览器实现的不同。

实现原理:它不需要麦克风权限,而是生成一个数学上的声音信号(正弦波、三角波等),通过压缩器(DynamicsCompressor)等节点处理后,分析输出的音频数据流。

核心代码

function getAudioFingerprint() {
  return new Promise((resolve, reject) => {
    // 1. 创建离线音频上下文
    const context = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 44100, 44100);

    // 2. 创建振荡器并生成三角波信号
    const oscillator = context.createOscillator();
    oscillator.type = 'triangle';
    oscillator.frequency.setValueAtTime(10000, context.currentTime);

    // 3. 创建压缩器,增强处理过程中的软硬件特性
    const compressor = context.createDynamicsCompressor();

    // 4. 连接节点:振荡器 -> 压缩器 -> 输出扬声器
    oscillator.connect(compressor);
    compressor.connect(context.destination);

    // 5. 启动并开始渲染
    oscillator.start(0);
    context.oncomplete = (event) => {
      // 6. 获取渲染后的音频数据
      const renderedBuffer = event.renderedBuffer;
      const outputData = renderedBuffer.getChannelData(0);

      // 7. 对音频数据采样求和,生成最终的指纹
      let hash = 0;
      for (let i = 0; i < outputData.length; i++) {
        // 简单的哈希算法,生产环境应使用更复杂的方法
        hash += Math.abs(outputData[i]);
      }
      resolve(hash.toString());
    };
    context.startRendering();
  });
}

工作原理:不同设备处理“三角波”并通过“压缩器”时,由于硬件和软件的差异,会引入极其微小的、独特的处理痕迹。通过计算生成的PCM音频数据流的摘要,就能获得一个高度唯一的音频指纹。

3. WebGL渲染特征

WebGL指纹通过暴露底层的显卡和驱动信息来识别设备,它提供了比Canvas指纹更直接的硬件标识符。

实现原理:通过WebGL API,可以查询到GPU的详细硬件参数,并与Canvas结合,像Canvas指纹那样通过渲染特定3D场景来获取图像哈希值。

核心代码

function getWebGLFingerprint() {
  // 1. 创建Canvas并获取WebGL上下文
  const canvas = document.createElement('canvas');
  const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  if (!gl) return null;

  // 2. 获取调试渲染信息(GPU型号等核心特征)
  const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
  const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL); // 显卡供应商
  const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL); // 显卡型号

  // 3. 收集其他稳定参数
  const parameters = {
    vendor: vendor,
    renderer: renderer,
    maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE), // 最大纹理尺寸
    maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS), // 最大视口尺寸
  };

  // 4. 将收集到的信息生成指纹
  const fingerprintString = JSON.stringify(parameters);
  // 5. 转换为哈希值(此处为简单示例)
  let hash = 0;
  for (let i = 0; i < fingerprintString.length; i++) {
    const char = fingerprintString.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash |= 0;
  }
  return hash.toString();
}

工作原理:代码会返回不同操作系统、GPU和浏览器组合下的渲染器字符串(如下所示),这些信息构成了设备在WebGL下的“身份证”。

Windows (NVIDIA): ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)

macOS (Apple M1): ANGLE (Apple, ANGLE Metal Renderer: Apple M1 Pro, Unspecified Version)

总结与最佳实践

为了生成一个高唯一性且稳定的浏览器指纹,通常需要组合使用以上多种技术

最佳实践

组合使用:综合Canvas、AudioContext、WebGL,并结合其他信息(如屏幕分辨率、字体列表、用户代理等),可生成一个熵值极高的唯一指纹。

稳健的哈希算法:为降低碰撞风险,建议使用SHA-256MurmurHash3等哈希算法,而非代码示例中的简单算法。

用户授权:某些浏览器(如Chrome)对AudioContext有自动播放策略限制,可能需要用户手势(如点击)才能启动。

隐私合规:在全球范围内(如GDPR),对用户进行指纹识别通常需要明确的知情同意。

网友回复

我知道答案,我要回答