返回知识中心
指纹

CreepJS WebGL 报告:上下文与能力信号

沿固定版本源码追踪 CreepJS WebGL 报告字段,区分上下文比较、renderer、像素读取和结论边界。

BotBrowser Team

文档中心

想直接进入 指纹 文档吗?

这篇文章属于知识中心的指南库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

CreepJS WebGL 报告不是一个图形值,也不是一次简单的通过或失败检查。在固定的公开实现中,不同代码路径分别采集 WebGL 与 WebGL2 参数、可选 renderer 元数据、着色器精度、canvas 图像数据和派生的能力摘要。把这些字段合并成一个判定,会掩盖每个字段由哪个操作产生,以及实际进入了哪条错误处理路径。

BotBrowser 文档说明了由 profile 控制的 WebGL 行为及其验证方式,但并未声称 CreepJS 报告可以识别物理设备或预测其他网站的判定。这里要解决的问题更具体:从一个明确的实现版本追踪报告字段及条件分支,同时保留各类观察的边界。

BotBrowser 支持通过 profile 配置 WebGL,并可在获授权的环境中检查声明的浏览器行为;单凭 CreepJS 字段不能确定物理设备身份或其他网站的判定。

BrowserLeaks 使用另一套采集流程;WebGL 报告分析逐步追踪上下文发现、可选渲染器数据和缺失字段检查,不把这些结果归到 CreepJS 名下。

TL;DR

  • 检查的文件是 CreepJS commit 10aa6724cd33a1015db1574211890518cd04f0cc 中的 src/webgl/index.ts。静态阅读只能说明源码结构,不能证明当前网站行为或 BotBrowser 实测结果。
  • 函数分别创建 WebGL 和 WebGL2 上下文。WebGL 上下文缺失时函数结束此路径,但可见分支没有要求 WebGL2 上下文也必须可用才继续。
  • 镜像比较会把 WebGL2 参数映射中的选定值与 WebGL 映射中的 truthy 值比较,并跳过 ALIASED_LINE_WIDTH_RANGE、SHADING_LANGUAGE_VERSION 和 VERSION。
  • WEBGL_debug_renderer_info、着色器精度、canvas 数据 URI 和 readPixels 输出是不同的观察。一个通道缺少数据不能解释另一个通道。
  • 派生能力分支可能在某个值不在内置列表时设置 LowerEntropy.WEBGL。这是该固定实现的行为,不是普遍 WebGL 规则,也不是对个人的判断。

目录

分开的路径展示 WebGL 上下文、参数比较、可选 renderer、canvas 导出、像素读取和派生能力。

两个上下文启动不同的采集路径

源码为 webgl 上下文创建一个 canvas,为 webgl2 创建另一个,然后分别使用对应名称调用 getContext。函数会检查第一个上下文是否存在。如果不存在,CreepJS 会记录 webgl 测试失败并从这条路径返回。在这一位置,代码没有对 gl2 做等价的提前返回检查;后续 helper 对缺失上下文的处理方式不同。

阅读精简报告时,这个顺序很重要。WebGL 路径失败并不表示两种上下文都已成功测试且返回相同结果。源码也没有说明第一个上下文为什么不可用。创建结果可能受到浏览器支持、canvas 状态、资源条件和应用代码影响。报告字段本身不能确定适用哪种解释。

这一区分对自有诊断页有帮助。页面代码可以分别记录 webgl_context_created 和 webgl2_context_created,并在配置过程抛出异常时另行保留错误。在两次尝试都得到明确定义的结果之前,不应写入单个 graphics_supported 布尔值。这种建议的记录方式用于理解应用自身的采集流程;它不是 CreepJS 的输出格式,也不是浏览器标准 API。

采集事件固定源码能说明什么仍然未知的内容
WebGL 上下文缺失此函数会记录 webgl 测试失败并停止该路径请求为何没有生成上下文,或重试是否会得到不同结果
WebGL 存在、WebGL2 缺失流程会越过第一道检查;接收缺失上下文的 helper 可能返回空数据或 undefined后续报告字段是否为特定使用方保留了这一区别
两个上下文引用都存在后续参数与渲染 helper 可以接收这两个引用每个可选扩展和读取操作是否都会成功
字段赋值前配置过程抛出异常外层错误处理可能返回错误形式的结果如果没有连同错误保留阶段信息,就无法知道哪个操作失败

这是控制流图,不是兼容性矩阵。上下文可用不代表所有可选扩展都存在,成功创建上下文也不保证绘图缓冲区可读。应用比较浏览器版本时,应分别记录请求的上下文、调用结果和后续操作。这样能明确显示采集代码的变化,避免把它误认为图形能力变化。

WebGL 指纹概览介绍更广泛的信息暴露面和 BotBrowser profile 控制。固定版本的 src/webgl/index.ts 分别构造上下文结果、参数比较、可选 renderer 元数据、着色器精度、canvas 与像素输出,以及派生能力字段。WebGL renderer 缺失状态分析讨论应用侧的状态,例如未请求字段、上下文不可用或丢失、扩展不可用;它不追踪 CreepJS 的输出组装流程。

镜像比较只覆盖条件限定的范围

为两个上下文构造参数对象后,实现会定义三个不参与镜像比较的键:ALIASED_LINE_WIDTH_RANGE、SHADING_LANGUAGE_VERSION 和 VERSION。差异列表从 WebGL2 对象的键中生成。候选键还必须在 WebGL 对象中有 truthy 值、不属于排除项,并且两个对象中的字符串表示不同。只有结果列表非空时,报告分支才会运行。

遍历 WebGL2 参数对象中的每个键:
  仅当 WebGL[key] 为 truthy 时保留
  跳过 ALIASED_LINE_WIDTH_RANGE、SHADING_LANGUAGE_VERSION、VERSION
  比较 String(WebGL[key]) 和 String(WebGL2[key])
只在至少剩下一个键时报告差异

这是一种有用的源码检查方式,因为它同时展示覆盖范围和遗漏之处。它不是对两个上下文暴露的所有值作穷尽相等断言。仅出现在 WebGL 对象中的属性不会被遍历。WebGL 侧的 falsey 值不会通过 truthy 条件。字符串转换可能隐藏的差异,也可能与数组或类型化值的结构比较不同。无论值是什么,三个被排除的键都不在这项检查范围内。

输入形态示例会进入源码差异列表吗?原因
两个映射中,未排除键具有相同 truthy 值不会字符串表示相同
两个映射中,未排除键具有不同 truthy 值会字符串表示不同
WebGL 值为 0、false、''、null 或 undefined不会过滤条件要求 WebGL 侧的值为 truthy
WebGL2 映射中不存在该键不会实现遍历 WebGL2 的键
键为 VERSION 或另外两个排除键之一不会显式排除映射会将其过滤

这些情况描述的是固定源码中可见的谓词,并不声称某个浏览器实际返回了什么值。检查指定 commit 中的 VersionParam 对象、Object.keys(params2) 过滤器以及 mismatch.length 条件,就能复核这个推理。这一区分可以避免过度解读:“报告没有显示差异”不等于所有 WebGL 和 WebGL2 输出都相等;它仅表示该谓词针对收到的数据生成了空列表。

报告也不会告诉维护者,差异源于实现缺陷、不支持的值、序列化、上下文缺失还是采集逻辑变化。这些是可调查的方向,不是分支本身给出的结论。如果原因很重要,诊断记录应保留字段名称和采集阶段;汇总成“WebGL 差异”计数会丢掉区分情况所需的证据。

renderer 字段与精度字段不能互换

源码先收集每个上下文的参数值。然后在 WEBGL_debug_renderer_info 可用时加入未屏蔽的 renderer 信息。helper 会向上下文请求该扩展;如果没有得到扩展对象,就返回空对象。如果扩展可用,它会通过 getParameter 读取 UNMASKED_VENDOR_WEBGL 和 UNMASKED_RENDERER_WEBGL。

这条可选扩展路径不同于常规上下文参数。Khronos 扩展规范定义了可选的未屏蔽 vendor 和 renderer 常量;MDN getParameter 参考说明了查询 API。这些来源都没有把扩展对象缺失解释为特定原因。它不能证明启用了隐私设置、缺少 GPU、策略作出了决定或应用存在某种意图;它仅表示 helper 没有通过这条路径添加这两个字段。

着色器精度是另一类字段。helper 会为 vertex 和 fragment shader 请求多种格式,包括低、中、高浮点精度以及高整数精度。随后,它会将 precision、rangeMax 和 rangeMin 属性写入与着色器阶段和格式关联的键中。这些字段描述的是当前上下文精度查询所返回的结果。它们不是 renderer 名称、扩展标志,也不能证明两个设备在物理上相同。

最终参数对象还会添加选定的上下文属性和限制。可见的组装代码包括 antialias 属性、MAX_VIEWPORT_DIMS、找到各向异性扩展时的最大纹理各向异性,以及找到相应扩展时的 MAX_DRAW_BUFFERS_WEBGL。某些查询由 attempt helper 包装,而依赖扩展的值可能缺失。因此,只要外围输出保留了区别,报告使用方就应分别表示“未出现”“未查询”和“查询发生错误”。

输出类别源码操作缺失值不能证明什么
标准参数遍历选定的参数名称并调用 getParameter浏览器不具备任何图形能力
未屏蔽 vendor/renderer请求 WEBGL_debug_renderer_info,再查询两个常量缺失是由隐私设置造成的
着色器精度对指定格式调用 getShaderPrecisionFormat稳定的设备身份或网站判定
可选限制查询依赖扩展的常量或上下文属性另一个独立查询是否会成功

这张表有意描述源码路径,而不是推荐的跟踪数据结构。renderer 字符串可能具有识别性,支持问题也未必需要它。产品应只收集完成已声明任务所需的数据,说明可选诊断,并避免把原始标签用作账户键。BotBrowser WebGL 文档介绍由 profile 控制的 BotBrowser 自身设置;CreepJS 源码并不能证明 BotBrowser 会在某人的设备上返回特定值。

canvas 导出与像素读取可能不一致

getWebGLData helper 会在上下文中绘制图案,并尝试生成两类输出。一类是 canvas 数据 URI;另一类是由 readPixels 填充的字节数组。源码读取绘图缓冲区尺寸,将宽和高分别除以 15 和 6 得到更小的尺寸,为每个采样像素分配 4 个字节,然后从左下角原点请求 RGBA 无符号字节值。

这个执行顺序会形成一个具体的部分失败情况。函数先尝试 toDataURL,之后才调用 readPixels。如果内部的 readPixels 调用抛出异常,catch 会返回已经得到的 dataURI,并把 pixels 设为 undefined。这不是一个全有或全无的结果。看到图像值存在但像素数据缺失,不应据此推断整个 WebGL 路径失败。反过来,data URI 缺失也不能证明曾尝试像素读取:更早发生的错误可能先进入外层 catch。

helper 对 OffscreenCanvas 还有特殊处理:它会创建普通 canvas 来生成数据 URI,并在其上绘制。像素读取仍绑定原来的 WebGL 上下文。因此,图像导出路径和像素路径通过绘制相关联,但它们不是同一个 API 调用或同一种输出表示。

失败位置数据 URI 路径像素路径解读边界
上下文参数缺失helper 返回未定义的输出字段不会读取该 helper 不说明上下文为何缺失
绘制或创建 data URI 时抛错外层错误处理会捕获错误尚未进入后续读取不应归类为 readPixels 失败
创建 URI 后 readPixels 抛错helper 可能返回 data URIpixels 变成 undefined两个字段没有共同的原子成功标志
两个操作都返回data URI 存在返回像素数组两个值都不能单独描述物理设备

维护自有渲染页面的工程师可以用这张图编写支持测试:分别记录是否执行了绘制、序列化是否完成、像素读取是否完成。将输出分开,既能评估备用路径,也避免保留超过支持问题所需的数据。采样网格不是标准化或唯一的指纹,任一输出也不能预测第三方是否接受某个会话。

能力摘要是在后续派生的

收集源字段后,模块会从通过 JavaScript truthy 条件且非字符串的顶层参数值创建标准化数字列表。Array.prototype.flat() 将数组展开一层;随后用 Number 转换得到的每个元素、移除重复项并按数值排序。代码再使用 renderer 字符串派生 GPU 品牌,并计算两个不同摘要:一个由品牌和参数向量生成的紧凑值,以及一个通过折叠数字列表得到的能力值。

模块会将这些派生值与内置列表比较。如果品牌能力值存在但不在品牌列表中,hasSusGpu 条件就为真。如果能力派生值存在但不在数字列表中,hasSusCapabilities 条件就为真。任一分支都可以设置 LowerEntropy.WEBGL,并使用相应标签调用 sendToTrash。之后源码会把 WebGL 测试记录为通过,并返回采集数据及 GPU 分类字段。

变量名里的“suspicious”属于实现的内部命名,不是标准化的可疑硬件定义。值不在源码列表中,可能源于列表更新、列表未覆盖的组合、缺失或转换后的参数,或运行环境。静态源码无法确定当前生成报告的浏览器符合哪种情况。

派生项源码中可见的输入该分支不能证明什么
webglParams通过 truthy 条件且非字符串的顶层值;数组展开一层,再转为数字、去重并排序所有 WebGL 参数都存在,或该向量在不同版本间稳定
webglBrandCapabilities由 renderer 派生的品牌及参数向量的字符串形式renderer 字符串指向物理硬件,或派生值能唯一识别设备
webglCapabilities数字参数值及其排序后位置参与的折叠结果是行业标准的能力标识
LowerEntropy.WEBGL 分支对内置品牌和能力数组进行成员检查普遍的 bot 判定、账户身份或策略原因

原始字段与派生摘要有重要区别。原始字段可以追溯到一个 WebGL API 调用;摘要则可能依赖采集后的标准化、排序、紧凑值函数、查询列表和 truthy 检查。如果最终报告变化,应先比较源码版本及这些转换步骤,不应直接把变化归因于物理 GPU。

CreepJS 信号组分析介绍报告如何组织独立的浏览器表面。跨组交叉检查与判定分析讨论组合与决策逻辑。WebGL 模块的派生分支使用自身收集的字段和内置列表;单看这一分支不能说明跨组聚合逻辑。

解读报告时保留证据边界

严谨的源码检查从固定版本开始。可变的主分支中,同一路径可能在报告保存后发生变化。固定 commit 10aa6724cd33a1015db1574211890518cd04f0cc 和 src/webgl/index.ts 路径可以让行引用和控制流说明可复核,但仍不能证明线上网站部署了该版本、某份具体报告由它生成,或某个浏览器执行了其中每条路径。

检查报告时,只记录回答问题所需的事实:

  1. 找到可见字段及其输出类别:上下文、参数、可选扩展、着色器查询、数据 URI、像素数组或派生摘要。
  2. 归因前,将字段对应到固定源码中的函数和分支。
  3. 当源码或报告暴露这些状态时,分别保留缺失、undefined、空值、错误和存在值。
  4. 检查一个值是直接比较、转成字符串、标准化、转换还是与列表匹配。
  5. 只陈述观察到的分支支持的有限结论;没有观察到的原因保持未定。

这些步骤适用于隐私审查、回归分析和第三方报告解释,不需要编造设备身份。源码快照能说明给定输入下代码会如何处理;它既不提供这些输入,也不能证明未观察到的分支执行过。

常见问题

WebGL renderer 缺失是否表示 WebGL 已禁用?

不是。renderer 字段来自可选扩展 WEBGL_debug_renderer_info,而上下文创建是单独检查的。此路径可能已经有上下文,但没有加入未屏蔽的 renderer 值。仅凭字段缺失无法确定原因。

镜像比较会比较所有 WebGL 值吗?

不会。它遍历 WebGL2 参数对象的键,要求对应的 WebGL 值为 truthy,跳过三个指定键,并比较字符串形式。空差异列表仅适用于这个谓词及其收到的数据。

LowerEntropy.WEBGL 是否表示浏览器是 bot?

固定版本模块会在某个派生值不在内置列表中时设置此内部标记。源码没有把它定义为通用 WebGL 标准;仅凭该字段也无法确定网站对访客的判定。

data URI 成功是否意味着 readPixels 也成功?

不意味着。helper 先序列化,再读取像素。内部读取错误的 catch 可以在像素数据为 undefined 时仍返回 data URI。这两个字段的完成状态不同。

来源

实践结论

应将报告视为一组依赖源码版本的观察,而不是单一设备标签。固定实现版本,分别保留生成每个值的上下文和操作,并区分可选 renderer 数据、图像序列化、像素读取和派生能力分支。字段缺失时,只在源码支持的范围内描述缺失;不要推断原因或其他网站的判定。

#Creepjs#Webgl#浏览器指纹#图形能力#隐私

本文属于指南: 什么是浏览器指纹?原理、风险、信号与隐私边界

让 BotBrowser 从研究走向生产

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