Consistencia de señales CSS con BotBrowser
Cómo las consultas de medios CSS y características como color-depth y prefers-color-scheme generan señales de huella digital, y cómo BotBrowser garantiza consistencia.
Introducción
El CSS suele pasarse por alto como vector de huella digital porque es ante todo un lenguaje de estilos. Sin embargo, las consultas de medios CSS exponen información sobre la pantalla, las preferencias y las capacidades del navegador del usuario. Propiedades como prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution y forced-colors revelan detalles de configuración del dispositivo que contribuyen a una huella digital. Lo que hace especialmente efectivo al fingerprinting basado en CSS es que funciona sin JavaScript. Una hoja de estilos construida con astucia puede extraer información del dispositivo mediante la carga condicional de recursos, haciéndolo invisible a las herramientas de privacidad basadas en scripts. Este artículo explica cómo las señales CSS contribuyen al fingerprinting y cómo BotBrowser asegura que las consultas de medios CSS, las llamadas JavaScript matchMedia() y las APIs relacionadas devuelvan valores consistentes y basados en el perfil.
Impacto en la privacidad
El fingerprinting por CSS ha ganado atención en la comunidad de investigación en privacidad porque opera en una capa distinta al fingerprinting por JavaScript. Un estudio mostró que al consultar 15+ características de medios simultáneamente, las características CSS por sí solas podían distinguir aproximadamente al 30% de los usuarios. Combinadas con propiedades accesibles desde JavaScript (que deben concordar con los valores CSS), la tasa de identificación aumenta significativamente.
La especificación W3C Media Queries Level 5 reconoce el potencial de fingerprinting de las características de medios. Características como prefers-color-scheme, prefers-contrast, prefers-reduced-motion y prefers-reduced-data revelan preferencias del usuario que varían en la población. Cada característica individual suele tener baja entropía (típicamente binaria o con pocas opciones), pero la combinación de muchas crea una huella significativa.
El fingerprinting CSS es preocupante porque puede operar sin ejecución de JavaScript. Un pixel de seguimiento cargado condicionalmente vía @media indica al servidor la configuración de pantalla del usuario solo por la petición. Incluso los usuarios que bloquean JavaScript por completo pueden ser parcialmente fingerprinted vía CSS.
Antecedentes técnicos
Características de medios CSS relevantes para fingerprinting
Las consultas de medios CSS prueban condiciones sobre el entorno del usuario. Las siguientes características son las más relevantes:
Propiedades de pantalla:
resolution/min-resolution/max-resolution— densidad de píxeles de la pantalla en dpi o dppx.color— número de bits por componente de color.color-index— número de colores en la tabla de búsqueda.color-gamut— gamut aproximado:srgb,p3orec2020.monochrome— si el dispositivo es monocromo y bits por píxel.
Preferencias de usuario:
prefers-color-scheme— preferencia:lightodark.prefers-reduced-motion— si se solicita reducir movimiento.prefers-contrast— si se solicita alto o bajo contraste.prefers-reduced-transparency— prefieren reducción de transparencia.forced-colors— modo de colores forzados (Windows High Contrast).
Viewport y pantalla:
width/height— dimensiones del viewport.device-width/device-height— dimensiones de la pantalla (deprecated pero soportadas).aspect-ratio— relación de aspecto.orientation—portraitolandscape.
Interacción:
hover— si el dispositivo primario puede hacer hover.any-hover— si cualquier dispositivo puede hacer hover.pointer— precisión del puntero:none,coarseofine.any-pointer— existencia de puntero disponible.
Cómo funciona el fingerprinting por CSS
El fingerprinting por CSS puede realizarse de dos formas.
Basado en JavaScript: Usando window.matchMedia() para probar consultas de medios:
const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const highDPI = window.matchMedia('(min-resolution: 2dppx)').matches;
const p3Gamut = window.matchMedia('(color-gamut: p3)').matches;
Puro CSS (sin JavaScript): Usando carga condicional de recursos:
@media (prefers-color-scheme: dark) {
.tracker { background-image: url('https://track.example.com/dark'); }
}
@media (prefers-color-scheme: light) {
.tracker { background-image: url('https://track.example.com/light'); }
}
El servidor determina la preferencia de esquema según la URL solicitada. Enlazando múltiples condiciones, una hoja CSS puede extraer decenas de señales binarias sin ejecutar JS.
Por qué varían las señales CSS
Los valores de características CSS dependen de:
- Hardware. Las capacidades del monitor determinan gamut, profundidad de color y resolución.
- Configuración OS. Dark mode, high contrast, reduced motion son preferencias a nivel del sistema.
- Configuración del navegador. Algunos navegadores sobreescriben preferencias del sistema. El modo privado puede alterar valores.
- Tipo de dispositivo. Dispositivos táctiles reportan
pointer: coarseyhover: none; escritorios reportanpointer: fineyhover: hover.
El problema de la consistencia
Los valores CSS y JS deben coincidir. Si matchMedia('(prefers-color-scheme: dark)').matches es true pero screen.colorDepth sugiere una configuración diferente, o si recursos CSS cargados contradicen valores reportados por JS, la inconsistencia es en sí misma una señal de fingerprinting.
Enfoques comunes de protección y sus limitaciones
Extensiones de navegador pueden interceptar matchMedia() pero no modificar reglas @media en hojas de estilo. Una página puede usar CSS puro para detectar valores mientras la extensión solo controla la API JS, creando una inconsistencia detectable.
Desactivar CSS rompe la web, no es viable.
Estandarizar preferencias (siempre reportar light, sin reduced motion, srgb) reduce huella pero crea un subconjunto distintivo. Usuarios que reportan todos los valores por defecto son raros y podrían destacar.
Tor Browser estandariza muchos valores CSS para reducir fingerprinting, pero esto produce una huella Tor reconocible.
El reto es asegurar que media features, matchMedia() y propiedades DOM relacionadas (por ejemplo screen.colorDepth) retornen valores controlados desde una única fuente.
Enfoque de BotBrowser a nivel de motor
BotBrowser controla las características de medios en el motor Chromium, asegurando consistencia entre CSS y API JavaScript.
Fuente de señal unificada
Al cargar un perfil, todos los valores de pantalla y preferencias provienen del perfil:
- Esquema de color controlado por
--bot-config-color-scheme. Tanto@media (prefers-color-scheme: ...)comomatchMedia()devuelven el mismo valor. - Dimensiones de pantalla provienen de la configuración del perfil.
@media (width: ...)yscreen.widthcoinciden. - Device pixel ratio del perfil controla
@media (resolution: ...)ydevicePixelRatio. - Profundidad de color controla
@media (color: ...)yscreen.colorDepth. - Pointer y hover coinciden con el tipo de dispositivo perfilado.
Alineación CSS-JS
BotBrowser garantiza que no haya discrepancias entre lo que @media ve y lo que JS reporta, porque ambos leen la misma configuración a nivel de motor.
Esto aplica para:
@media (prefers-color-scheme: dark)↔matchMedia('(prefers-color-scheme: dark)')@media (min-resolution: 2dppx)↔window.devicePixelRatio@media (pointer: fine)↔matchMedia('(pointer: fine)')@media (color-gamut: p3)↔matchMedia('(color-gamut: p3)')
Carga condicional de recursos
Como las características de medios se controlan en el motor, incluso el fingerprinting puro por CSS devuelve valores consistentes con el perfil. Un @media que carga un pixel de seguimiento según el esquema de color verá el esquema del perfil, no la preferencia del sistema.
Consistencia cross-contexto
Las características de medios son consistentes en:
- Hojas de estilo del documento principal
- Hojas de estilo del Shadow DOM
matchMedia()desde cualquier contexto JS- Contenido de iframes (same-origin y cross-origin)
- Media queries para impresión
Configuración y uso
Carga básica de perfil
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Las señales CSS se configuran automáticamente desde el perfil.
Control de esquema de color
# Forzar modo claro
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=light
# Forzar modo oscuro
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-color-scheme=dark
Configuración de pantalla
# Usar ajustes de pantalla y ventana del perfil
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-screen=profile \
--bot-config-window=profile
# Deshabilitar override de device scale factor
chrome --bot-profile="/path/to/profile.enc" \
--bot-config-disable-device-scale-factor=true
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-color-scheme=light',
'--bot-config-screen=profile',
'--bot-config-window=profile'
]
});
const page = await browser.newPage();
await page.goto('https://example.com');
const signals = await page.evaluate(() => ({
darkMode: window.matchMedia('(prefers-color-scheme: dark)').matches,
highDPI: window.matchMedia('(min-resolution: 2dppx)').matches,
finePointer: window.matchMedia('(pointer: fine)').matches,
hoverCapable: window.matchMedia('(hover: hover)').matches,
colorDepth: screen.colorDepth,
devicePixelRatio: window.devicePixelRatio
}));
console.log(signals);
Verificación
Consistencia CSS-JS. Para cada característica, compare el valor evaluado por CSS con el valor reportado por JavaScript. matchMedia('(prefers-color-scheme: dark)').matches debe coincidir con el comportamiento de render.
Render del esquema de color. Visite un sitio con soporte dark mode; el render debe coincidir con --bot-config-color-scheme.
Consistencia DPI. Compare window.devicePixelRatio con matchMedia('(resolution: 2dppx)').matches.
Pointer y hover. Verifique que matchMedia('(pointer: fine)').matches refleje el perfil.
Estabilidad entre sesiones. Ejecutar las mismas verificaciones con el mismo perfil debe devolver los mismos valores.
Buenas prácticas
- Establezca el esquema de color explícitamente. Use
--bot-config-color-scheme=lightodark. - Ajuste pointer/hover al tipo de dispositivo. Desktop
pointer: fine, mobilepointer: coarse. - Use configuraciones de pantalla del perfil.
--bot-config-screen=profiley--bot-config-window=profile. - Pruebe con CSS y JS. Verifique
@mediaymatchMedia()conjuntamente. - Considere el impacto del dark mode en capturas. Para comparaciones visuales, mantenga el esquema consistente.
Preguntas frecuentes
P: Pueden las webs fingerprintearme solo con CSS sin JS?
R: Sí. La carga condicional de recursos vía @media permite extraer valores sin JS. BotBrowser controla la evaluación en el motor, así que incluso detecciones puras por CSS usan valores controlados.
P: prefers-reduced-motion afecta las animaciones?
R: Sí. Cuando prefers-reduced-motion: reduce está activo, los sitios bien diseñados reducen o desactivan animaciones. Los perfiles BotBrowser establecen esta preferencia de acuerdo al dispositivo del perfil.
P: Cuánta entropía aportan las características CSS? R: Cada característica suele aportar 1-3 bits. Combinando 15+ características se pueden alcanzar 10-15 bits en condiciones favorables.
P: BotBrowser maneja forced-colors?
R: Sí. forced-colors (modo High Contrast de Windows) está controlado por el perfil; la configuración estándar suele ser forced-colors: none.
P: Qué hay de dynamic-range?
R: dynamic-range (standard o high) indica capacidad HDR; los perfiles incluyen esta información según el dispositivo fuente.
P: Son consistentes las características dentro de iframes? R: Sí. El control a nivel de motor se aplica a todos los contextos de renderizado, incluidas iframes same-origin y cross-origin.
Resumen
Las características CSS ofrecen una superficie de fingerprinting independiente de JavaScript que revela configuración de pantalla, preferencias y capacidades de interacción. BotBrowser controla las características de medios en el motor Chromium, asegurando que @media, matchMedia() y propiedades DOM devuelvan valores consistentes derivados del perfil. Con --bot-config-color-scheme y ajustes de pantalla basados en perfil, BotBrowser elimina la brecha entre lo observado por CSS y lo reportado por JavaScript.
Temas relacionados: What is Browser Fingerprinting、Screen and Window Protection、Font Fingerprint Protection、Navigator Property Protection.
title: "Consistencia de senales CSS con BotBrowser" description: "Como BotBrowser asegura que las media queries CSS y las APIs de JavaScript devuelvan valores coincidentes mediante control de perfil a nivel del motor del navegador." date: "2025-06-18" locale: es category: fingerprint tags: ["css", "fingerprinting", "privacy", "color-depth", "media-queries"] published: true
El riesgo de privacidad
Las media queries CSS exponen informacion del dispositivo - profundidad de color, resolucion de pantalla, preferencia de esquema de color, tipo de puntero - sin ejecutar JavaScript. Un servidor puede detectar estos valores puramente a traves del comportamiento de carga de hojas de estilo, haciendo esta superficie dificil de observar y controlar.
El desafio critico: los resultados de media queries CSS deben coincidir con los valores de las APIs de JavaScript. Las herramientas basadas en extensiones solo pueden modificar los valores de retorno de JavaScript mientras dejan la evaluacion de media queries CSS intacta, creando brechas detectables.
La solucion de BotBrowser
BotBrowser controla las senales relacionadas con CSS a nivel del motor del navegador. Cuando se carga un perfil, el estado interno del navegador se configura para que todas las media queries CSS y sus contrapartes JavaScript lean de la misma fuente.
Configuracion basada en perfil
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Este unico flag establece las propiedades de pantalla, profundidad de color, relacion de pixeles del dispositivo y valores de caracteristicas de medios. Las consultas CSS como (color: 8), (prefers-color-scheme: light) y (pointer: fine) reflejan el dispositivo objetivo del perfil.
Sin brecha entre CSS y JS
Porque BotBrowser modifica los datos de plataforma subyacentes en lugar de parchear APIs individuales, no hay brecha entre lo que CSS evalua y lo que JavaScript reporta.
Verificacion
Despues de cargar un perfil, verifica la alineacion entre CSS y JavaScript:
const { chromium } = require('playwright-core');
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
defaultViewport: null,
});
const page = await (await browser.newContext()).newPage();
const results = await page.evaluate(() => {
const cssColor = matchMedia('(color: 8)').matches;
const jsDepth = screen.colorDepth;
const cssWidth = matchMedia(`(device-width: ${screen.width}px)`).matches;
const cssPointer = matchMedia('(pointer: fine)').matches;
const touchPoints = navigator.maxTouchPoints;
return {
colorConsistent: cssColor === (jsDepth === 24),
widthConsistent: cssWidth,
pointerConsistent: cssPointer === (touchPoints === 0),
};
});
console.log('Consistencia CSS/JS:', results);
// Todos los valores deben ser true
Verificaciones clave:
matchMedia('(color: 8)')coincide conscreen.colorDepthmatchMedia('(device-width: Xpx)')coincide conscreen.widthmatchMedia('(pointer: fine)')coincide connavigator.maxTouchPoints
Primeros pasos
- Descarga BotBrowser desde GitHub
- Carga un perfil de huella digital con
--bot-profile - Establece
defaultViewport: nullen Playwright o Puppeteer para que el perfil controle las dimensiones - Verifica la consistencia CSS y JavaScript usando DevTools o herramientas de prueba