Huella digital

Fingerprinting WebGL: controla la identidad de tu GPU

Cómo las cadenas de renderer WebGL y la salida de renderizado revelan la identidad de tu GPU. Aprende técnicas a nivel de motor para controlar las señales de huella digital WebGL.

Documentación

Prefieres la documentación del producto mantenida?

Este artículo tiene una página equivalente en el centro de documentación. Usa los docs para el flujo canónico, las flags actuales y la referencia duradera.

Introducción

WebGL (Web Graphics Library) permite el renderizado 3D acelerado por hardware dentro del navegador. Los sitios web lo usan para juegos, visualización de datos, mapas y contenido interactivo. Pero WebGL también expone información detallada sobre tu GPU: el nombre del fabricante, la cadena del renderer, extensiones soportadas, formatos de precisión y la salida a nivel de píxel de las operaciones de renderizado. Los sistemas de rastreo recopilan estos valores para construir una huella digital de GPU que es altamente estable y difícil de cambiar. Debido a que las configuraciones de GPU varían ampliamente entre dispositivos, la huella digital WebGL puede distinguir usuarios incluso cuando otras señales son idénticas. Este artículo explica cómo funciona la huella digital WebGL, por qué las protecciones comunes no son suficientes, y cómo BotBrowser controla la identidad de GPU a nivel del motor de renderizado.

Impacto en la privacidad

La huella digital WebGL está entre las señales de rastreo más poderosas disponibles. La investigación de Inria y KU Leuven encontró que las cadenas de renderer de GPU por sí solas pueden reducir una población de usuarios a grupos de menos de 100. Cuando se combina con la salida de renderizado (dibujar una escena específica y leer los datos de píxeles), la unicidad aumenta dramáticamente.

Un estudio de 2020 de la Universidad de Illinois demostró que el renderizado WebGL produce salida específica del dispositivo porque las GPUs implementan la aritmética de punto flotante, el muestreo de texturas y la ejecución de shaders con ligeras diferencias a nivel de hardware. Dos GPUs de diferentes fabricantes, incluso ejecutando el mismo código de shader, producen framebuffers visualmente similares pero numéricamente distintos.

La escala de despliegue es significativa. Según el Princeton Web Transparency and Accountability Project, se encontraron scripts de huella digital WebGL en más del 7% de los sitios web del top 10,000 de Alexa. La técnica se ha convertido en un componente estándar en las bibliotecas de rastreo comerciales y se usa junto con la huella digital de canvas, audio y fuentes para construir identificadores compuestos.

La huella digital WebGL alcanza la GPU a través de tres superficies independientes. El diagrama siguiente muestra qué recolecta un rastreador de cada superficie y cómo los tres flujos se combinan en un identificador compuesto único.

Three surfaces, one GPU fingerprint Surface 1: Identity strings WEBGL_debug_renderer_info UNMASKED_VENDOR_WEBGL UNMASKED_RENDERER_WEBGL vendor + GPU model + driver Narrows population to fewer than 100 Surface 2: Parameter queries gl.getParameter(...) MAX_TEXTURE_SIZE shaderPrecisionFormat getSupportedExtensions ~50 numeric properties that vary by GPU class Surface 3: Rendering output readPixels(...) hash draw test scene read framebuffer pixels SHA hash the buffer Pixel-level divergence from float and texture math Composite GPU fingerprint Stable across cookie clears, IP changes, and incognito Defense must address all three surfaces simultaneously. Spoofing one and leaking the other two is itself a signal.

La tercera superficie es lo que hace que la huella digital WebGL sea difícil de derrotar. Las cadenas y parámetros pueden reescribirse mediante JavaScript, pero la salida de readPixels proviene del cómputo real de la GPU. Una defensa que devuelve una cadena de fabricante de GPU Mac mientras el framebuffer transporta patrones de píxeles de una iGPU Intel queda detectada por cualquier verificación cruzada que hashee ambas superficies y compare.

Contexto técnico

WebGL expone la identidad de GPU a través de varios mecanismos.

Cadenas de renderer y vendor

La exposición más directa proviene de la extensión WEBGL_debug_renderer_info:

gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
// "ANGLE (NVIDIA GeForce RTX 3080, D3D11)"

gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
// "Google Inc. (NVIDIA)"

Estas cadenas revelan el fabricante de la GPU, el modelo y a veces la versión del driver de gráficos. Son suficientemente únicas para reducir significativamente la población de usuarios.

Salida de renderizado

La salida de renderizado WebGL varía a nivel de píxel debido a diferencias de hardware. Un script de huella digital podría dibujar una escena compleja con shaders específicos, gradientes y transparencia, luego leer el framebuffer con readPixels(). Los datos de píxeles resultantes se hashean para producir un identificador estable.

Las fuentes de variación en el renderizado incluyen:

  • Precisión de punto flotante. Diferentes GPUs manejan las operaciones float con diferente comportamiento de redondeo, particularmente en los fragment shaders.
  • Filtrado de texturas. Las implementaciones de filtrado bilineal y trilineal varían entre fabricantes.
  • Anti-aliasing. La implementación predeterminada de MSAA difiere entre arquitecturas de GPU.
  • Optimizaciones a nivel de driver. Los drivers de GPU aplican optimizaciones específicas del fabricante que afectan la salida de píxeles.

Consultas de parámetros

WebGL expone docenas de parámetros de capacidad a través de getParameter():

  • MAX_TEXTURE_SIZE, MAX_VIEWPORT_DIMS, MAX_RENDERBUFFER_SIZE
  • MAX_VERTEX_ATTRIBS, MAX_VARYING_VECTORS, MAX_FRAGMENT_UNIFORM_VECTORS
  • ALIASED_LINE_WIDTH_RANGE, ALIASED_POINT_SIZE_RANGE
  • Formatos de textura comprimidos soportados, formatos de precisión de shaders y extensiones

Cada uno de estos valores refleja las capacidades de la GPU y contribuye a la huella digital general.

Extensiones WebGL2

WebGL2 añade superficie adicional. Parámetros como MAX_3D_TEXTURE_SIZE, MAX_ARRAY_TEXTURE_LAYERS y MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS diferencian aún más el hardware. El método getShaderPrecisionFormat() devuelve detalles de precisión por tipo de shader, que varían entre familias de GPU.

El diagrama siguiente muestra cómo el mismo código de prueba WebGL produce huellas digitales distintas en cuatro clases comunes de GPU. Cada fila es una implementación real que los rastreadores ven en sus datos.

Same WebGL code, four GPU classes, four fingerprints GPU class UNMASKED_RENDERER_WEBGL readPixels SHA-256 (prefix) NVIDIA discrete Windows + RTX 3080 ANGLE (NVIDIA, GeForce RTX 3080, D3D11) vendor: Google Inc. (NVIDIA) 2c6d031696... FP16 fast, full extension set Apple Silicon macOS + M2 Pro ANGLE (Apple, ANGLE Metal Renderer: Apple M2 Pro) vendor: Google Inc. (Apple) 9c18bdc539... tile-based deferred rendering Intel iGPU Windows + Iris Xe ANGLE (Intel, Iris Xe Graphics, D3D11) vendor: Google Inc. (Intel) 5c41b9d30f... restricted FP16 ranges Mesa llvmpipe (software) Linux server, no GPU Mesa OpenGL Engine, llvmpipe (LLVM JIT) vendor: Mesa 676363d51d... distinct precision profile Una combinación de cadenas de la fila A con píxeles de la fila D queda identificada con una sola verificación cruzada.

Enfoques comunes de protección y sus limitaciones

Bloquear WebGL por completo previene la huella digital pero rompe una gran porción de la web moderna. Mapas, visualizadores de productos 3D, dashboards de datos y juegos dependen de WebGL. Deshabilitarlo hace que tu navegador sea menos capaz y también crea una señal de huella digital distintiva: la ausencia de WebGL es en sí misma poco común y rastreable.

Suplantar las cadenas de renderer mediante una extensión de navegador puede cambiar lo que devuelve UNMASKED_RENDERER_WEBGL, pero esto solo aborda una parte de la huella digital. La salida de renderizado real aún proviene de tu GPU real. Un sitio puede dibujar una escena de prueba, leer los píxeles y determinar tu clase de GPU real a partir de las características de renderizado. La discrepancia entre la cadena reportada y el comportamiento de renderizado es en sí misma una señal fuerte.

Añadir ruido a la salida de readPixels mediante intercepción JavaScript modifica los datos del framebuffer devueltos. Pero la inyección de ruido es detectable: renderizar la misma escena dos veces debería producir salida idéntica. Si no lo hace, hay inyección de ruido presente. Algunas extensiones intentan cachear y reproducir el ruido, pero este enfoque falla con escenas dinámicas y llamadas de dibujo variadas.

Usar renderizado por software (como SwiftShader o Mesa llvmpipe) produce salida consistente entre hardware pero crea su propia huella digital distintiva. Los renderers de software tienen un comportamiento de precisión y valores de parámetros característicos que los identifican específicamente.

El desafío central es que la huella digital WebGL combina parámetros reportados con salida de renderizado real. La protección efectiva debe controlar ambos simultáneamente.

El enfoque a nivel de motor de BotBrowser

BotBrowser controla la identidad WebGL a nivel del motor de renderizado de Chromium, asegurando que los parámetros reportados y la salida de renderizado real sean ambos consistentes con el perfil cargado.

El diagrama siguiente apila los cuatro modelos comunes de defensa WebGL frente al tipo de verificación cruzada que ejecuta un sistema moderno de huella digital. Cada modelo por encima de la capa del motor deja una discrepancia medible entre cadenas, parámetros y píxeles.

Defense layers and the cross-check that breaks each one 1. Block WebGL entirely getContext('webgl') returns null. Real browsers almost always succeed. Detection: presence of WebGL context is itself a baseline check. 2. Spoof renderer strings via JS shim UNMASKED_RENDERER_WEBGL returns a fake string but readPixels still uses real GPU. Detection: hash a known scene, compare against the table for the claimed GPU class. 3. Inject noise into readPixels output Per-load noise breaks stability: rendering the same scene twice should match. Detection: render the same scene twice and compare. Mismatch flags noise injection. 4. Engine-level rendering control (BotBrowser) Strings, parameters, and pixel output all originate from the same profile-bound pipeline. No JavaScript wrapper to detect. No mismatch between reported GPU and rendered pixels. Same profile + same noise seed reproduces identical hashes across hosts.

Control de identidad de GPU

Cuando se carga un perfil de huella digital, BotBrowser configura el subsistema WebGL para reportar la identidad de la GPU perfilada:

  • Las cadenas de renderer y vendor coinciden con el dispositivo objetivo. Un perfil para un sistema con una Intel UHD 630 reporta las cadenas exactas de renderer y vendor de esa GPU.
  • Los valores de parámetros (tamaño máximo de textura, dimensiones de viewport, formatos de precisión, etc.) todos coinciden con las capacidades de la GPU perfilada. No son valores aleatorios. Corresponden a configuraciones de hardware reales.
  • Las listas de extensiones reportan exactamente las extensiones soportadas por la GPU perfilada. No se añaden ni eliminan extensiones comparado con el dispositivo real.

Consistencia de la salida de renderizado

El sistema de perfiles de BotBrowser incluye información sobre las características de renderizado de la GPU objetivo. Cuando se combina con el flag --bot-noise-seed, la salida de renderizado se vuelve determinista y consistente con el dispositivo perfilado. El motor aplica variación controlada que produce datos de píxeles de apariencia auténtica sin exponer tu GPU real.

Esto cubre:

  • Precisión de salida de fragment shaders
  • Comportamiento de muestreo de texturas
  • Datos de readPixels() para cualquier escena dibujada
  • Resultados de getShaderPrecisionFormat()
  • Operaciones de blending de framebuffer

Cobertura WebGL2

Los mismos controles aplican a WebGL2. Parámetros, extensiones y comportamiento de renderizado se derivan todos del perfil. No hay brecha entre la protección de WebGL1 y WebGL2.

Consistencia entre APIs

BotBrowser asegura que los datos WebGL se alineen con otras señales del perfil. La GPU reportada por WebGL coincide con lo que aparece en navigator.userAgentData, lo que produce el renderizado de canvas y lo que reporta WebGPU (si está habilitado). Esta consistencia entre APIs es crítica porque los sistemas de rastreo comúnmente verifican cruzadamente las señales relacionadas con GPU a través de múltiples APIs.

Configuración y uso

Protección básica WebGL

Carga un perfil para configurar todos los parámetros WebGL:

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

Anulación de configuración WebGL

Controla el comportamiento WebGL independientemente:

# Usar configuración WebGL del perfil (predeterminado)
chrome --bot-profile="/path/to/profile.enc" \
       --bot-config-webgl=profile

# Usar GPU real del sistema (sin protección WebGL)
chrome --bot-profile="/path/to/profile.enc" \
       --bot-config-webgl=real

# Deshabilitar WebGL por completo
chrome --bot-profile="/path/to/profile.enc" \
       --bot-config-webgl=disabled

Renderizado determinista con semilla de ruido

Para huellas digitales WebGL reproducibles:

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

Integración con Playwright

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

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

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

Integración con 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-config-webgl=profile',
    '--bot-noise-seed=42'
  ]
});

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

Control separado de ruido de imagen WebGL

# Deshabilitar ruido de imagen WebGL manteniendo otra protección WebGL
chrome --bot-profile="/path/to/profile.enc" \
       --bot-config-noise-webgl-image=false

Verificación

Para verificar que la protección WebGL funciona:

Verificación de cadena de renderer. Abre la consola del navegador y consulta UNMASKED_RENDERER_WEBGL. El valor debe coincidir con la GPU objetivo del perfil, no con tu hardware real.

Consistencia de parámetros. Verifica varios parámetros WebGL (MAX_TEXTURE_SIZE, formatos de precisión, lista de extensiones) y confirma que coincidan con los valores esperados para la GPU perfilada.

Estabilidad entre sesiones. Ejecuta la misma rutina de huella digital WebGL en dos sesiones con el mismo perfil y semilla de ruido. Los resultados deben ser idénticos.

Estabilidad entre máquinas. Ejecuta la prueba en diferente hardware con el mismo perfil y semilla. La huella digital WebGL debe coincidir.

Visita BrowserLeaks, CreepJS o sitios similares de prueba de huella digital para comparar tu salida WebGL con los valores esperados de tu perfil.

La matriz de verificación siguiente muestra cómo se ve el éxito en tres hosts ejecutando el mismo perfil. Cadenas UNMASKED idénticas, hashes de readPixels idénticos para WebGL1 y WebGL2, lista de extensiones idéntica, independientemente del hardware del host.

Cross-platform verification: same profile, identical WebGL signature Windows host running BotBrowser profile = mac_arm64.enc seed = 100 UNMASKED_RENDERER ANGLE Metal · M2 Pro vendor: Apple webgl1: 0f9829ee244b webgl2: b879347569e8 macOS host running BotBrowser profile = mac_arm64.enc seed = 100 UNMASKED_RENDERER ANGLE Metal · M2 Pro vendor: Apple webgl1: 0f9829ee244b webgl2: b879347569e8 Linux host (Xvfb) running BotBrowser profile = mac_arm64.enc seed = 100 UNMASKED_RENDERER ANGLE Metal · M2 Pro vendor: Apple webgl1: 0f9829ee244b webgl2: b879347569e8 Mismo perfil + misma semilla = cadenas UNMASKED idénticas, hash WebGL1 idéntico, hash WebGL2 idéntico. Cadenas y píxeles permanecen alineados.

Mejores prácticas

  • Usa --bot-config-webgl=profile (predeterminado). Esto asegura que todos los parámetros WebGL provengan del perfil. Solo cambia a real si necesitas acceso nativo a la GPU específicamente.
  • Combina con --bot-noise-seed para salida determinista. Sin semilla, el ruido de renderizado WebGL varía entre sesiones. Una semilla fija asegura reproducibilidad.
  • Mantén la configuración WebGL y WebGPU alineada. Si tu perfil tiene datos de WebGL y WebGPU, mantén ambos en profile para conservar la consistencia. Una discrepancia entre la GPU reportada por WebGL y WebGPU es una inconsistencia detectable.
  • No anules manualmente las cadenas de renderer. BotBrowser maneja esto a través del perfil. Establecer cadenas de renderer manualmente sin coincidir con el comportamiento de renderizado crea inconsistencias.
  • Prueba con sitios verificadores de huella digital. Verifica que tu huella digital WebGL coincida con las expectativas antes de desplegar en producción.

Preguntas frecuentes

P: ¿La huella digital WebGL funciona sin la extensión WEBGL_debug_renderer_info? R: Parcialmente. Sin la extensión, las cadenas de renderer y vendor no están disponibles, pero la salida de renderizado, los valores de parámetros y los formatos de precisión aún varían según la GPU. La huella digital basada en renderizado por sí sola es a menudo suficiente para reducir la población de usuarios.

P: ¿Puedo usar BotBrowser con aplicaciones intensivas en WebGL como juegos 3D? R: Sí. El control WebGL de BotBrowser opera a nivel de identidad y huella digital. El rendimiento de renderizado proviene de tu GPU real. Los juegos y aplicaciones 3D funcionan normalmente.

P: ¿La protección WebGL afecta la huella digital de canvas? R: Canvas 2D y WebGL usan diferentes rutas de renderizado, pero BotBrowser controla ambos a través del perfil. Producen resultados consistentes que se alinean con el mismo dispositivo perfilado.

P: ¿Qué pasa si un sitio solicita extensiones WebGL que no están en mi perfil? R: BotBrowser reporta solo las extensiones listadas en el perfil. Las solicitudes de extensiones no soportadas devuelven null, consistente con el comportamiento de la GPU perfilada.

P: ¿WebGL2 se protege por separado de WebGL1? R: Ambos están controlados por el mismo perfil y configuración. El flag --bot-config-webgl aplica tanto a contextos WebGL1 como WebGL2.

P: ¿Cómo maneja BotBrowser WebGL en Web Workers? R: Los contextos WebGL de OffscreenCanvas en workers están sujetos a los mismos controles a nivel de motor que los contextos del hilo principal. La huella digital es consistente en ambos.

Resumen

La huella digital WebGL combina cadenas de identidad de GPU, parámetros de capacidad y salida de renderizado a nivel de píxel para crear una señal de rastreo poderosa. Debido a que llega a la capa de hardware, las protecciones basadas en JavaScript no pueden abordarla completamente. BotBrowser controla la identidad y el renderizado WebGL a nivel del motor de Chromium, asegurando que cada superficie de API devuelva valores consistentes con el perfil de huella digital cargado. Combinado con --bot-noise-seed para salida determinista y --bot-config-webgl para control explícito, BotBrowser proporciona protección completa de huella digital WebGL.

Para temas relacionados, consulta Qué es la huella digital del navegador, Protección de huella digital WebGPU, Huella digital de Canvas y Protección de huella digital de audio.

#Webgl#fingerprinting#Gpu#Privacy#Webgl2

Lleva BotBrowser de la investigación a producción

Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.