指纹

确定性模式:可重现的浏览器指纹

如何使用噪声种子控制在不同会话间产生相同的浏览器指纹,实现一致的 Canvas、WebGL 和 Audio 输出。

文档中心

想直接进入 指纹 文档吗?

这篇文章属于博客内容库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

简介

浏览器指纹追踪依赖于在会话内稳定但在设备间变化的信号。这个问题的另一面是可重现性:当你需要多个浏览器会话呈现相同的身份,或者需要验证你的隐私保护是否正常工作时,你需要确定性行为。一个每次启动都产生略微不同的 Canvas 哈希、Audio 指纹或 WebGL 输出的浏览器,使得维护稳定身份或可靠测试配置变得不可能。BotBrowser 的确定性模式通过 --bot-noise-seed 标志启用,让你完全控制所有指纹变化来源。相同的配置文件和种子组合始终产生相同的指纹,跨会话、跨机器、跨操作系统。

隐私影响

确定性浏览器行为的需求源于指纹保护中的一个根本矛盾。噪声对隐私很重要。给 Canvas 输出、Audio 处理和 WebGL 渲染添加受控的变化可以防止指纹被简单地关联到单个配置文件。但不受控的噪声,即每个会话产生不同指纹,会产生另一个问题:每个会话看起来都是唯一用户,这与融入群体恰恰相反。

INRIA 隐私团队的研究表明,指纹不稳定性(跨会话的指纹变化)本身就是一个追踪信号。如果指纹在每次访问时都变化,但其他信号(IP、登录状态、行为模式)保持稳定,变化的指纹就成为标记而非屏障。

确定性模式通过给你明确的控制来解决这个问题。你选择指纹何时应保持相同(相同种子)以及何时应不同(不同种子)。这对以下场景特别重要:

  • 会话连续性。 跨多个会话以相同指纹返回网站。
  • 多实例协调。 运行需要不同但稳定身份的多个浏览器实例。
  • 测试和验证。 确认你的指纹保护产生预期结果。
  • 研究可重现性。 运行需要消除指纹变化作为变量的受控实验。

技术背景

指纹变化的来源

现代指纹保护涉及向多个渲染和处理管线添加受控噪声:

  • Canvas 2D。 文本渲染、形状绘制和图像操作产生设备特定的像素输出。噪声添加亚像素变化以防止精确匹配。
  • WebGL/WebGPU。 着色器执行、纹理采样和帧缓冲区读回产生 GPU 特定的输出。噪声修改渲染输出中的像素值。
  • Audio。 OfflineAudioContext 渲染和 AnalyserNode 频率数据产生平台特定的浮点值。噪声改变处理输出。
  • 文本指标。 measureText()getBoundingClientRect()getClientRects() 返回依赖于字体渲染的尺寸。噪声添加亚像素变化到测量值。

没有种子时,每个噪声源在每次浏览器启动时生成全新的随机变化。有种子时,随机数生成器被初始化为已知状态,每次都产生相同的变化模式。

噪声种子的工作原理

噪声种子是一个单独的整数,用于初始化确定性伪随机数生成器(PRNG)。PRNG 产生一个看起来随机但完全由种子决定的值序列。两个具有相同种子的会话产生相同的序列,因此对每个指纹表面应用相同的噪声。

BotBrowser 的噪声种子(通过 --bot-noise-seed 设置)控制:

  • Canvas 2D 图像噪声
  • WebGL 图像噪声
  • WebGPU 渲染噪声
  • Audio 上下文处理变化
  • 文本指标变化(客户端矩形、文本矩形)
  • 文本布局变化

种子不影响非噪声属性如 navigator.hardwareConcurrencyscreen.width 或用户代理字符串。这些直接来自配置文件,始终是确定性的。

时序确定性

除了指纹噪声之外,BotBrowser 还提供额外的时序控制:

  • --bot-time-seed - 控制 27 个浏览器操作的执行时序多样性。每个种子产生独特、稳定的性能配置文件。这覆盖 performance.now() 间隔、performance.getEntries()、导航时序等。
  • --bot-time-scale - 缩小 performance.now() 间隔以归一化因不同服务器负载造成的时序差异。

噪声种子和时序种子结合使用,提供对所有可变浏览器输出的全面确定性控制。

常见保护方案及其局限性

完全不加噪声意味着你的指纹直接反映配置文件的基础值。这是确定性的,但消除了变化带来的隐私收益。具有相同配置文件的多个会话都有完全相同的指纹,意味着它们按定义是可关联的。

没有种子的随机噪声提供变化,但以可重现性为代价。每个会话都有唯一的指纹。你无法维护稳定的身份,无法可靠地验证配置,也无法协调多个实例。

基于会话的噪声(每个会话生成随机种子并存储)是一种手动解决方案,增加了复杂性。你需要管理种子值,将它们与会话关联,并确保一致应用。BotBrowser 通过将种子作为 CLI 标志接受来消除这种开销。

基于扩展的噪声通常在 JavaScript 级别应用随机噪声,没有任何种子机制。每次页面加载产生不同的结果。噪声不是确定性的、不可控的,也不是跨 API 表面一致的。

BotBrowser 的引擎级方案

BotBrowser 的确定性模式在渲染引擎级别运行,确保从单个种子值出发,噪声在所有 API 表面一致应用。

单一种子,完整覆盖

--bot-noise-seed 标志接受从 1 到 4294967295(UINT32_MAX)的整数。这个单一值同时控制所有噪声源:

  • Canvas 2D 的 toDataURL()toBlob()getImageData() 对相同种子产生相同输出。
  • WebGL 的 readPixels() 对相同绘制场景和种子返回相同的帧缓冲区数据。
  • OfflineAudioContext 对相同的音频图和种子渲染相同的缓冲区。
  • measureText()getClientRects() 对相同内容和种子返回相同的测量值。

跨机器可重现性

由于噪声从种子派生并在引擎级别应用,相同的配置文件 + 种子组合无论底层硬件、操作系统或 GPU 如何都产生相同的指纹。一个使用 NVIDIA GPU 的 Linux 服务器上的会话和一个使用 Apple Silicon 的 Mac 笔记本上的会话,在使用相同配置文件和种子时产生相同的指纹。

种子作为身份

实际上,你可以将每个种子视为在配置文件内定义唯一子身份。配置文件 A 加种子 42 是一个稳定、可重现的身份。配置文件 A 加种子 43 是另一个稳定、可重现的身份。配置文件定义设备类别(操作系统、浏览器、硬件),种子定义该类别中的个体。

这个模型自然映射到多账户或多会话工作流:

  • 会话 1:配置文件 A,种子 100
  • 会话 2:配置文件 A,种子 200
  • 会话 3:配置文件 B,种子 100

会话 1 和 2 看起来是具有相似硬件的不同用户。会话 3 看起来是使用不同硬件的不同用户。

时序确定性

使用 --bot-time-seed,执行时序也变得可重现。性能测量、导航时序和资源时序都遵循给定种子的确定性模式。与 --bot-noise-seed 结合使用,这提供了对所有可变浏览器输出的完整控制。

Deterministic Mode: Seed Controls All Noise Sources --bot-noise-seed=42 Deterministic PRNG Canvas Noise WebGL Noise Audio Noise Text Metrics Same seed = Same fingerprint every time

配置和用法

基本确定性模式

chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=42 \
       --user-data-dir="$(mktemp -d)"

完整确定性控制

chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=42 \
       --bot-time-seed=42 \
       --bot-stack-seed=profile \
       --user-data-dir="$(mktemp -d)"

使用不同种子的多实例

# 实例 1 - 稳定身份 A
chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=1001 \
       --user-data-dir="/tmp/session-a" &

# 实例 2 - 稳定身份 B
chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=1002 \
       --user-data-dir="/tmp/session-b" &

Playwright 集成

const { chromium } = require('playwright');

const browser = await chromium.launch({
  executablePath: '/path/to/botbrowser/chrome',
  args: [
    '--bot-profile=/path/to/profile.enc',
    '--bot-noise-seed=42',
    '--bot-time-seed=42'
  ]
});

const page = await browser.newPage();
await page.goto('https://example.com');

// 此 Canvas 指纹在每次运行中都完全相同
const hash = await page.evaluate(() => {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.fillText('deterministic test', 10, 10);
  return canvas.toDataURL();
});
console.log(hash);

Puppeteer 集成

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch({
  executablePath: '/path/to/botbrowser/chrome',
  defaultViewport: null,
  args: [
    '--bot-profile=/path/to/profile.enc',
    '--bot-noise-seed=42',
    '--bot-time-seed=42'
  ]
});

const page = await browser.newPage();
await page.goto('https://example.com');

禁用特定噪声通道

如果你需要某些信号的确定性输出但其他信号使用原生输出:

chrome --bot-profile="/path/to/profile.enc" \
       --bot-noise-seed=42 \
       --bot-config-noise-canvas=false \
       --bot-config-noise-audio-context=false

验证

跨会话可重现性。 使用相同配置文件和种子在两个独立会话中运行相同的指纹测试。比较 Canvas 哈希、Audio 指纹、WebGL 输出和文本指标。所有值应完全相同。

跨机器可重现性。 在不同机器上使用相同配置文件和种子运行相同测试。指纹应完全匹配。

种子变化。 更改种子并再次运行测试。指纹应不同,确认种子确实在影响输出。

种子 0 的行为。 使用 --bot-noise-seed=0 保持噪声激活(使用配置文件默认值),但不进行确定性种子设置。验证这会在会话之间产生变化的输出。

最佳实践

  • 为每个身份使用唯一种子。 每个种子定义一个稳定的子身份。不要对应该呈现为不同用户的会话重用相同种子。
  • 存储种子值。 如果你需要返回某个会话,你需要相同的配置文件和种子。存储会话身份与种子值之间的关联。
  • --bot-noise-seed--bot-time-seed 结合使用。 噪声种子控制渲染输出。时序种子控制性能计时。两者都参与完整指纹。同时使用两者以实现完全确定性。
  • 避免种子值 0。 零保持噪声激活但变化不确定。使用任何正整数实现确定性行为。
  • 测试你的种子分配。 在部署之前,验证不同种子产生不同指纹,相同种子产生相同指纹。

常见问题

问:--bot-noise-seed 的有效范围是什么? 答:从 1 到 4294967295(UINT32_MAX)的任何整数。值 0 保持噪声激活但不确定。

问:噪声种子是否影响浏览器性能? 答:不影响。噪声操作极其轻量。PRNG 计算增加的开销可以忽略不计。

问:两个不同的配置文件使用相同种子能产生相同的指纹吗? 答:不能。配置文件定义基础指纹(GPU、屏幕、navigator 等),种子定义噪声变化。不同配置文件使用相同种子会产生不同的指纹,因为基础值不同。

问:如果我不设置 --bot-noise-seed 会怎样? 答:每次启动时用随机种子应用噪声。每个会话有不同的指纹。配置文件的基础属性(navigator、screen 等)保持不变。

问:确定性模式是否影响 Cookie 或本地存储? 答:不影响。确定性模式控制与指纹相关的渲染输出。存储、Cookie 和会话状态通过 --user-data-dir--bot-cookies 管理。

问:我可以在不同的 BotBrowser 版本之间使用相同种子吗? 答:噪声算法可能在主版本之间发生变化。为了精确可重现性,请使用相同的 BotBrowser 版本。在同一版本内,种子行为保证稳定。

问:--bot-time-seed 与 --bot-noise-seed 有何不同? 答:--bot-noise-seed 控制渲染噪声(Canvas、WebGL、Audio、文本指标)。--bot-time-seed 控制执行时序多样性(performance.now() 模式、导航时序)。它们是独立的,可以设置为不同的值。

总结

确定性浏览器行为对于维护稳定的指纹身份、协调多会话工作流和验证隐私保护至关重要。BotBrowser 的 --bot-noise-seed 标志提供对所有指纹变化来源的完整控制,无论底层硬件如何,对相同配置文件和种子组合产生相同的输出。结合用于时序确定性的 --bot-time-seed 和用于栈深度控制的 --bot-stack-seed,BotBrowser 提供了覆盖每个可变浏览器输出的全面确定性模式。

相关主题请参阅什么是浏览器指纹Audio 指纹保护Canvas 指纹追踪以及噪声种子可重现性

#Deterministic#Noise-Seed#Reproducibility#浏览器指纹识别#Privacy

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。