WebGL 不仅用于炫酷的网页特效,还能通过 GPU 渲染差异精准追踪用户。深入了解 WebGL 指纹如何提取显卡与驱动信息,以及有哪些有效的防范手段。
WebGL 指纹通过查询你的显卡硬件、并观察它渲染 3D 场景的具体方式来识别设备。由于显卡型号、驱动版本和操作系统的每一种组合都会产生略有差异的输出、并报告略有不同的能力参数,网站无需任何授权、Cookie 或本地存储,就能读取你的 GPU 厂商与渲染器字符串、枚举支持的扩展和数值上限,并把渲染出的图像哈希成一个稳定的标识。这使得 WebGL 成为现代浏览器指纹中信息熵最高的信号之一。
WebGL 是什么,为何会暴露硬件身份
WebGL 是一套 JavaScript API,让网页能够低层级地访问 GPU,实现硬件加速的二维和三维图形渲染。它本质上是浏览器对 OpenGL ES 的绑定,这意味着当你调用 WebGL 时,请求会穿过浏览器、穿过图形驱动,一直抵达机器内部那块物理显卡。
正是这种深层访问让它成为指纹采集的富矿。为了高效绘图,WebGL 必须暴露硬件的能力——支持多大的纹理、有哪些可选特性、着色器如何对浮点数取整。同时它产生的输出也因硬件而异:同一段绘制指令,在 NVIDIA 显卡、苹果 GPU 和 Intel 集成显卡上会得到略有差别的像素,因为它们对光栅化、抗锯齿和浮点运算的实现各不相同。
WebGL 信号大致分为两类:声明型元数据(显卡自我报告的字符串和数值)和渲染输出(实际绘制场景时产生的像素)。两者共同补充了Canvas 指纹检测所探测的二维渲染路径,也一起汇入我们在浏览器指纹完整指南中描述的整体画面。
高信息量的数据点
显卡厂商与渲染器字符串
WebGL 中辨识度最高的单项信号,是未屏蔽的厂商与渲染器字符串。默认情况下标准的 VENDOR 和 RENDERER 参数只返回通用值,但 WEBGL_debug_renderer_info 扩展会暴露真实的硬件身份——例如 Google Inc. (NVIDIA) 以及 ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11) 这样的字符串。
这条字符串往往会透露你的 GPU 型号、渲染后端(Direct3D、Metal、或经由 ANGLE 的 OpenGL),有时还包括驱动信息。仅凭它就能把你缩小到一小撮用户之中,因为精确的「GPU+后端」组合远比人们想象的更稀有。
支持的扩展列表
WebGL 自带一组核心特性,外加数十个可选扩展。getSupportedExtensions() 返回的列表——以及它的排列顺序——取决于显卡、驱动和浏览器版本。两台显卡型号相同的设备,如果驱动或浏览器构建不同,这里仍可能出现差异,从而又增加一层区分度。
数值参数与着色器精度
WebGL 暴露了一长串反映硬件能力的数值上限:MAX_TEXTURE_SIZE、MAX_VIEWPORT_DIMS、MAX_RENDERBUFFER_SIZE、走样线宽与点尺寸范围,以及顶点和片元着色器可用的最大 uniform 向量数。着色器精度——通过 getShaderPrecisionFormat() 查询高/中/低精度的浮点和整型格式——进一步增加了细粒度,因为精度行为与芯片本身紧密相关。
基于渲染的哈希
最强大的技术与 Canvas 指纹如出一辙,只是改由 GPU 驱动。脚本会渲染一个刻意设计得很「刁钻」的场景——渐变、光照、透明度、曲面几何——用 readPixels() 把像素读回并做哈希。不同 GPU 和驱动在浮点取整、抗锯齿和纹理过滤上的差异,会产生一个在硬件家族之间各不相同、但对同一设备保持稳定的哈希。由于它捕捉的是行为而非仅仅是声明值,要令人信服地伪造它要难得多。
代码层面的实际观察
下面的代码片段收集了指纹脚本会采集的核心 WebGL 信号。你可以通过 BrowserInsight 的指纹检测工具查看自己浏览器的等效实时结果。
function getWebGLFingerprint() {
const canvas = document.createElement('canvas');
const gl =
canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) return { supported: false };
// 1. 通过 debug 扩展读取未屏蔽的 GPU 厂商与渲染器
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const vendor = debugInfo
? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
: gl.getParameter(gl.VENDOR);
const renderer = debugInfo
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
: gl.getParameter(gl.RENDERER);
// 2. 数值能力上限
const params = {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS),
maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),
aliasedLineWidth: gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE),
};
// 3. 片元高精度浮点格式的着色器精度
const precision = gl.getShaderPrecisionFormat(
gl.FRAGMENT_SHADER,
gl.HIGH_FLOAT
);
// 4. 支持的扩展列表(存在与否、顺序都有信息量)
const extensions = gl.getSupportedExtensions();
return {
supported: true,
vendor,
renderer,
params,
precision: { rangeMin: precision.rangeMin, prec: precision.precision },
extensions,
};
}
基于渲染的哈希则更进一步:它编译一个着色器,绘制一个带光照的渐变图形,调用 gl.readPixels() 把结果读入一个类型化数组,再把该数组送入哈希函数。得到的值对你的设备保持恒定,却在不同硬件之间各不相同。
WebGL 增加了多少信息熵
信息熵衡量一个信号能把「你是谁」缩小到何种程度。WebGL 对追踪者格外有价值,恰恰因为它携带的信息熵很高且十分稳定:你的显卡不会在两次页面加载之间改变,大多数用户也从不更新驱动。厂商/渲染器字符串、扩展列表、数值上限和渲染哈希之间存在部分相关——它们都源自同一块硬件——但每一项都捕捉到了别项遗漏的细节。
实际上 WebGL 极少单独使用。它会与 Canvas、音频、字体、屏幕尺寸以及数十种其他属性组合在一起。下表对比了主要的 WebGL 信号类型,以及各自被伪造的难易程度。
| WebGL 信号 | 暴露的内容 | 稳定性 | 伪造难度 |
|---|---|---|---|
| 厂商/渲染器字符串 | GPU 型号+渲染后端 | 极高 | 易于覆盖,但会破坏一致性 |
| 支持的扩展列表 | 驱动+浏览器特性集 | 高 | 中等——列表须保持自洽 |
| 数值参数 | 硬件能力上限 | 极高 | 中等——各值相互关联 |
| 着色器精度 | 浮点运算行为 | 高 | 难——与真实芯片绑定 |
| 渲染像素哈希 | 真实的 GPU 渲染行为 | 高 | 极难——须伪造真实输出 |
由于元数据必须与渲染输出彼此吻合,粗糙的伪造往往反而增加唯一性:一台报告 Intel 渲染器字符串、却产出 NVIDIA 风格像素的设备,比一台老老实实如实上报的设备更扎眼。
网站如何使用 WebGL 指纹
正当用途很常见。反欺诈和反机器人系统会把 WebGL 指纹作为众多信号之一,用来发现自动化流量、无头浏览器,以及硬件突然变更的账户。分析与安全团队用它来标记可疑会话。无头和虚拟化环境常常暴露出标志性的渲染器字符串(例如 SwiftShader 或 llvmpipe 这类软件光栅器),这正是机器人检测如此倚重 WebGL 的原因。
同样的能力也被用于跨站广告与追踪,因为一个基于硬件的稳定 ID 能在清除 Cookie 和无痕窗口中存活下来。正是这种双重用途,使得无论你关注的是安全还是隐私,理解 WebGL 指纹都很重要。
防御手段及其取舍
没有完美的防御——每种方案都会以牺牲功能、性能或「融入人群」的能力为代价。主要思路如下:
Tor 浏览器
Tor 浏览器走的是标准化路线:它出厂时配置统一,使所有用户呈现相同的指纹,并在允许 WebGL 之前先弹窗询问。目标不是隐藏你的显卡,而是让每个用户看起来都一模一样,这是最强的隐私模型——代价是速度下降以及部分 3D 内容失效。
Brave 与 Farbling
Brave 会对可指纹化的输出(包括 WebGL 读回结果)加入微小、确定性、且「按会话+按站点」变化的随机扰动(称为「farbling」)。每个站点看到的值都略有不同,且噪声会重新洗牌,因此难以构建稳定的跨站 ID,而大多数页面仍能正常工作。
完全禁用 WebGL
通过开关或 webgl.disabled 彻底关闭 WebGL,会完全移除这一采集面。它有效但很「粗暴」:WebGL 的缺席本身就有几分不寻常,还会让地图、游戏和可视化工具失效。
数值伪造——以及它为何会适得其反
覆盖渲染器字符串或注入噪声的扩展可能有帮助,但确有风险。如果伪造的元数据与渲染像素或数值上限相互矛盾,成熟的检测器会察觉到这种不一致,于是你反而变得更易识别,而非更难。最安全的伪造应当一致、且为众多用户所共用;缺乏协同、各用户自行其是的随机化,常常事与愿违。
务实的结论是:选择一个被许多人共用的防御方案(Tor 的统一性、Brave 的 farbling),而不是一套让你变得独一无二的定制配置。想了解自己当前的处境,请运行 BrowserInsight 的指纹检测工具,查看你的 WebGL 渲染器、扩展和哈希。
WebGL 也并非 GPU 指纹采集的终点。更新的 WebGPU API 将适配器厂商、架构和设备字符串作为一等属性直接暴露——无需任何调试扩展——构成了更丰富的采集面,而大多数隐私工具尚未覆盖到它。
常见问题
网站能读取我确切的显卡型号吗?
在大多数浏览器中可以。WEBGL_debug_renderer_info 扩展会暴露一条未屏蔽的渲染器字符串,常常点出你的 GPU 型号和渲染后端。一些隐私浏览器会限制或随机化它,但在默认的 Chrome 或 Edge 配置下,它无需任何授权弹窗即可被读取。
隐私/无痕模式下 WebGL 指纹仍然有效吗?
是的。无痕浏览会清除 Cookie 和历史记录,但不会改变你的硬件。WebGL 信号——厂商、渲染器、扩展、数值上限和渲染哈希——在普通窗口和无痕窗口中保持一致,因此能在两者之间重新识别你。
禁用 WebGL 足以阻止指纹追踪吗?
它移除了 WebGL 这一采集面,但并未消除整体的指纹追踪。Canvas、音频、字体、屏幕等其他信号依旧适用,而 WebGL 的显眼缺席本身也可能成为一种区分特征。禁用它是一层防护,而非完整方案。
WebGL 指纹与 Canvas 指纹有何不同?
Canvas 指纹探测的是二维渲染路径,而 WebGL 探测的是由 GPU 驱动的三维路径,并额外暴露显式的硬件元数据(厂商、渲染器、能力上限)。两者相关但不同,这正是追踪者会同时采集二者以提高置信度的原因。


