Volver al Centro de conocimiento
Huella digital

Fingerprinting CSS: cómo las hojas de estilo te rastrean

Cómo las media queries CSS como color-gamut y prefers-color-scheme crean señales de huella, y cómo mantener coherentes los valores de CSS y JavaScript.

BotBrowser Team

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.

Se suele describir CSS como un lenguaje de estilo, no como una superficie de rastreo. Sin embargo, las media queries permiten que una hoja de estilo pregunte al navegador por la pantalla, los ajustes de la persona y los dispositivos de entrada disponibles, y las respuestas varían de un grupo de usuarios a otro. Características como prefers-color-scheme, prefers-reduced-motion, color-gamut, resolution, pointer y hover revelan cada una un pequeño dato de la configuración del dispositivo. Una hoja de estilo puede leer esos datos sin una sola línea de JavaScript, y por eso las herramientas de privacidad centradas en los scripts a veces la pasan por alto.

Ver el video

Este video en inglés muestra cómo una hoja de estilo puede informar al servidor del ajuste de modo oscuro de una persona sin ejecutar ningún script, y compara la respuesta de la hoja de estilo con lo que lee un script en una página de laboratorio local y en Chrome oficial en dos máquinas. No usa ningún perfil de BotBrowser y no demuestra identidad, anonimato, acceso ni la decisión de un sitio remoto. El audio está en inglés.

La pregunta útil no es si una sola característica identifica a una persona. No lo hace. La pregunta es si los valores que una página ve mediante CSS coinciden con los que ve mediante JavaScript, y si se mantienen estables para la configuración que quieres presentar. Las secciones siguientes describen las características de medios implicadas, cómo la carga condicional las expone sin scripts, por qué las protecciones parciales dejan huecos, cómo comprobar la coherencia, qué pueden hacer los autores de sitios y qué cubre BotBrowser y qué no.

BotBrowser puede mantener las media queries CSS y los valores de pantalla relacionados alineados con un perfil cargado, incluido un esquema de color explícito y valores de pantalla definidos por el perfil. No controla lo que la hoja de estilo de un sitio solicita o registra, no hace anónima una sesión ni sustituye los ajustes de accesibilidad. Por eso, este artículo trata de la coherencia del perfil y sus límites, no de una promesa de anonimato.

Resumen

Las media queries CSS exponen valores de baja entropía sobre pantalla, preferencias y entrada, y la carga condicional de recursos puede revelarlos sin JavaScript. Mantén CSS y JavaScript basados en la misma fuente del perfil, prueba sesiones repetidas y entiende la alineación de BotBrowser como una ayuda de coherencia, no como una garantía de anonimato.

Índice

Una interfaz web adapta su movimiento, contraste, colores y tema a los ajustes del navegador, con un control visible para elegir una alternativa

Qué características de medios aportan señal

Las media queries de CSS comprueban condiciones del entorno en el que se muestra una página. Las características que más importan para el fingerprinting se dividen en cuatro grupos.

  • Pantalla. resolution, color, color-index, color-gamut y monochrome describen la densidad de píxeles, la profundidad de color y el rango de colores que la pantalla puede mostrar.
  • Preferencias. prefers-color-scheme, prefers-reduced-motion, prefers-contrast, prefers-reduced-transparency y forced-colors exponen decisiones tomadas en los ajustes del sistema operativo o del navegador.
  • Ventana y pantalla. width, height, aspect-ratio y orientation describen la ventana, mientras que los más antiguos device-width y device-height describen la pantalla.
  • Interacción. hover, any-hover, pointer y any-pointer indican a la página si el dispositivo principal puede pasar el cursor por encima y con qué precisión.

Cada valor procede de algo concreto. El hardware del monitor fija la gama, la profundidad y la resolución. Los ajustes del sistema operativo deciden el modo oscuro, el contraste y las preferencias de movimiento. La configuración del navegador puede sustituir a la del sistema, y los modos de navegación privada pueden cambiar ciertos valores. El tipo de dispositivo también cuenta: los dispositivos táctiles suelen informar pointer: coarse y hover: none, mientras que los ordenadores de escritorio informan pointer: fine y hover: hover.

¿Cuánto revela todo esto? La especificación W3C Media Queries Level 5 reconoce que las características de preferencias del usuario pueden contribuir al fingerprinting. Cada característica por sí sola tiene poca entropía, normalmente un booleano o unos pocos valores, a menudo de uno a tres bits. En conjunto, el panorama cambia. Un estudio de TU Graz informó de que las características de medios CSS por sí solas distinguían a aproximadamente tres de cada diez usuarios cuando se consultaban más de quince características a la vez, y se ha estimado que la entropía total ronda de 10 a 15 bits en condiciones favorables. Lee esas cifras como rangos publicados, no como garantías, porque dependen de la población medida y de cuántas características consulta la página.

Un cálculo aproximado muestra por qué importan las combinaciones. Siete características con dos o tres valores cada una ya permiten varios cientos de combinaciones distintas. Las combinaciones reales son menos, porque las características se correlacionan: un teléfono con puntero táctil casi nunca tiene hover, y un ordenador de escritorio con puntero preciso casi siempre lo tiene. La información efectiva es por tanto menor que el producto bruto, pero sigue siendo más de lo que sugiere cualquier característica aislada.

No todos los valores pesan lo mismo. Un valor común, como el modo claro en una pantalla de escritorio estándar, coloca al visitante en un grupo muy grande y dice poco al sitio. Un valor raro, como un modo forced-colors activo, una gama rec2020 o una petición de transparencia reducida, coloca al visitante en un grupo mucho más pequeño. Características más recientes como dynamic-range, prefers-reduced-data e inverted-colors añaden más dimensiones, y cada característica que un navegador incorpora a la plataforma es un valor más por el que una hoja de estilo puede preguntar. Por eso la combinación inusual suele ser más informativa que la común, y una combinación incoherente es la más informativa de todas.

Cómo una hoja de estilo lee valores sin JavaScript

Un script puede probar una media query directamente con window.matchMedia(), que indica si una condición se cumple en ese momento. Es el camino que vigilan la mayoría de las herramientas de privacidad.

const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const dense = window.matchMedia('(min-resolution: 2dppx)').matches;
const wide = window.matchMedia('(color-gamut: p3)').matches;

El segundo camino no necesita ningún script. Es la carga condicional de recursos, en la que una regla dentro de un bloque @media hace referencia a una URL.

@media (prefers-color-scheme: dark) {
  .tracker {
    background-image: url('https://stats.example.com/dark');
  }
}
@media (prefers-color-scheme: light) {
  .tracker {
    background-image: url('https://stats.example.com/light');
  }
}

El navegador solicita solo la imagen cuya condición se cumple, de modo que el servidor conoce el esquema de color del visitante por la URL que recibe. Si se repite el patrón con más condiciones, una sola hoja de estilo puede reunir muchas respuestas binarias: oscuro o claro, denso o estándar, puntero preciso o táctil. Como la información viaja en una petición normal, incluso quienes bloquean JavaScript por completo pueden ver su huella obtenida en parte por esta vía.

Las condiciones también se pueden combinar. Una regla como @media (prefers-color-scheme: dark) and (min-resolution: 2dppx) solo se cumple cuando las dos partes son ciertas, de modo que una hoja de estilo puede solicitar una URL por combinación en lugar de una por característica. Así el número de peticiones se mantiene bajo y aun así se separa a los visitantes por varias características a la vez, y una sola discrepancia entre dos caminos puede afectar al resultado de muchas reglas.

Conviene recordar dos propiedades de este camino. Primero, las media queries se reevalúan cuando cambia el entorno, así que pasar al modo oscuro a mitad de una visita provoca una nueva petición, y el cambio se hace visible con el tiempo y no solo en la carga. Segundo, las características de preferencias normalmente son comunes a todos los marcos de una página, mientras que las de ventana siguen el tamaño de cada marco, así que los valores pueden diferir entre un documento y un marco incrustado por motivos legítimos.

Por eso los dos caminos deben coincidir. La hoja de estilo y el script leen el mismo entorno, y un sitio puede comparar lo que informa cada uno. Si matchMedia('(prefers-color-scheme: dark)') dice una cosa mientras el recurso cargado por la hoja de estilo dice otra, o si screen.colorDepth y devicePixelRatio no concuerdan con las características CSS color y resolution, la discrepancia es una señal en sí misma, sean cuales sean los valores individuales.

Las media queries no son la única parte de CSS que refleja la plataforma. Las reglas @supports revelan qué propiedades y valores implementa el navegador, las palabras clave de colores del sistema se resuelven en colores definidos por el tema del sistema operativo, y las palabras clave de fuente como system-ui se resuelven en una fuente de la plataforma. Una hoja de estilo puede usar cualquiera de ellas para averiguar qué sistema operativo o familia de navegador produjo una página, y cada una debe mantenerse alineada con el resto de la configuración por la misma razón. Un perfil que describe una plataforma mientras los colores del sistema o la fuente del sistema siguen a otra produce el mismo tipo de discrepancia que una media query que contradice a matchMedia().

Por qué las protecciones habituales dejan huecos

Varios enfoques conocidos resuelven una parte del problema y dejan el resto.

  • Las extensiones que envuelven matchMedia() cambian lo que ven los scripts, pero la hoja de estilo sigue evaluando las reglas @media con la pantalla y los ajustes reales. Una página que usa carga condicional recibe el valor verdadero desde CSS y el valor modificado desde el script, de modo que la propia extensión crea la incoherencia.
  • Desactivar CSS no es práctico, porque la mayoría de los sitios dependen de él para ser utilizables.
  • Las preferencias estandarizadas, como informar siempre modo claro, sin movimiento reducido y con gama sRGB, reducen la variación pero crean un grupo distintivo. Un navegador que informa el valor por defecto en todas las preferencias puede destacar entre personas cuyos ajustes difieren.
  • Tor Browser estandariza muchos valores entre sus usuarios, lo que da un grupo grande y compartido, pero ese grupo es reconocible como Tor Browser.

Los modos de resistencia integrados en el navegador siguen un patrón parecido. Firefox ofrece un ajuste de resistencia al fingerprinting que informa valores fijos para varias características de preferencias, lo que da el mismo equilibrio que la estandarización: mucha menos variación dentro del grupo, pero un grupo reconocible por sus valores fijos. Ninguno de estos enfoques es incorrecto para el público al que se dirige. Simplemente responden a una pregunta distinta de la que aquí se plantea, que es cómo mantener coherente una configuración elegida en todos los caminos que una página puede usar.

Lo que queda es un requisito de coherencia, no de ocultación. Las características de medios CSS, matchMedia() y valores relacionados como screen.colorDepth y devicePixelRatio deben derivar de una única fuente, y esa fuente debe describir un dispositivo coherente. La política de relación de píxeles del dispositivo explica por qué la densidad es uno de los valores que más se comparan, y la guía sobre el fingerprinting de pantalla y ventana trata los valores de dimensiones que van a su lado.

Comprobar la coherencia de un perfil

Una comprobación útil compara la misma característica por dos caminos con un mismo perfil y repite después la comparación en una sesión posterior.

  • Esquema de color. Abre una página con tema oscuro y confirma que el tema mostrado y matchMedia('(prefers-color-scheme: dark)').matches coinciden entre sí y con el valor que configuraste.
  • Resolución. Compara window.devicePixelRatio con el resultado de matchMedia('(min-resolution: 2dppx)'). Ambos deben describir la misma densidad.
  • Profundidad de color y gama. Compara screen.colorDepth con la característica CSS color, y comprueba color-gamut frente a la pantalla que representa el perfil.
  • Puntero y hover. Confirma que pointer y hover encajan con el dispositivo de entrada principal que declara el perfil, que no siempre es el factor de forma: un perfil de teléfono suele informar coarse sin hover, mientras que un perfil de escritorio aún puede informar coarse o sin hover cuando su entrada declarada es una pantalla táctil.
  • Estabilidad. Repite las mismas comprobaciones en varias sesiones con el mismo perfil. Los valores deben ser idénticos cada vez.

Prueba tanto el camino de la hoja de estilo como el del script. Una pequeña página local cuyas reglas @media cambien el color de un elemento visible muestra lo que ve CSS, y la carga condicional lee los mismos valores. Si el renderizado y el resultado del script no coinciden, esa diferencia es lo primero que hay que corregir, antes de cualquier otro ajuste.

El modo oscuro también cambia el aspecto de las páginas. Si haces capturas de pantalla o comparas diseños entre ejecuciones, fija el esquema de color de forma explícita para que los resultados sigan siendo comparables. Un valor sin fijar que sigue al equipo anfitrión puede diferir entre un portátil y un servidor, y la diferencia aparecerá como un cambio visual que no tiene nada que ver con la página.

Incluye en la revisión los marcos incrustados y los estilos de impresión. Un marco evalúa sus propias reglas @media, así que una página de prueba que incruste un segundo documento muestra si las características de preferencias coinciden entre marcos, mientras que las de ventana siguen el tamaño de cada marco. Los estilos de impresión usan el tipo de medio print, que una página puede activar a propósito, de modo que una hoja de estilo con un bloque @media print es otro lugar donde se pueden leer valores relacionados con la pantalla. Trata esto como la misma comprobación repetida en otros contextos, no como problemas separados.

Cuando una comprobación falle, cambia una sola cosa cada vez. Empieza con un arranque de referencia en el que solo se cargue el perfil, anota los valores de ambos caminos, añade después una única opción, como el esquema de color o la fuente de pantalla, y compara de nuevo. Guarda en tus notas el comando de arranque final para que una sesión posterior pueda repetirlo con exactitud. Si el esquema de color no coincide con lo esperado, fíjalo de forma explícita en lugar de depender del valor por defecto. Si una consulta de características o un color del sistema apunta a una plataforma distinta de la que pretendías, comprueba primero que el perfil cargado describe la plataforma que querías usar, porque la disponibilidad de características sigue al perfil.

Una condición de aprobado para cada par

Par que se comparaSe aprueba cuando
prefers-color-scheme frente a matchMediaAmbos informan el mismo esquema en cada carga
devicePixelRatio frente a min-resolutionEl corte de la consulta coincide con la proporción informada
screen.colorDepth frente a colorscreen.colorDepth es al menos tres veces color
pointer / hover frente a la entradaAmbos coinciden con el dispositivo de entrada principal que describe el perfil

La lista anterior dice qué mirar; esta tabla dice cuándo esa mirada responde la pregunta. Sin una condición escrita, quien revisa compara dos valores a ojo y acepta el par que parece plausible, que es justo como una discrepancia sobrevive varias sesiones.

Escribe la condición antes de leer cualquiera de los dos valores y anota el resultado como verdadero o falso, no como un par de números. Una fila booleana es lo que hace comparables dos sesiones: las mismas cuatro filas, el mismo resultado esperado y un diff que muestra qué fila cambió.

Vigila las unidades. devicePixelRatio es una proporción como 2, mientras que min-resolution acepta dppx o dpi, así que (min-resolution: 2dppx) y (min-resolution: 192dpi) describen la misma densidad escrita de dos formas. Comparar una proporción con un valor en dpi produce una discrepancia que es un error de unidades y no un problema del perfil.

Vigila también la dirección de la comparación. (min-resolution: 2dppx) pregunta si la densidad es al menos dos, así que un perfil con proporción exactamente 2 aprueba y uno de 1.5 falla; ese es un resultado correcto, no un defecto. Anota la consulta exacta que usaste para que una sesión posterior no lea una consulta cambiada como una pantalla cambiada.

Dos filas merecen atención especial, y ninguna es una igualdad simple. CSSOM View exige que screen.colorDepth sea al menos tres veces el valor CSS color, porque el primero cuenta bits por píxel y el segundo bits por componente de color; la igualdad no es obligatoria ni está garantizada, así que compararlos como si tuvieran que coincidir informa un defecto donde no lo hay. La fila del puntero es la otra: Media Queries Level 5 define pointer y hover a partir del dispositivo de entrada principal y no del factor de forma, y permite explícitamente que una pantalla táctil sea la entrada principal en un equipo de escritorio, así que un perfil de escritorio puede informar pointer: coarse o hover: none y seguir siendo coherente. La gestión del color cubre el caso relacionado en el que una afirmación de gama supera a la pantalla que describe.

Qué pueden hacer los autores de sitios

Los autores de sitios tienen su propia parte en esto. Las consultas @media existen para que la presentación se adapte, y ese propósito merece protegerse. Unos pocos hábitos lo mantienen separado de la recogida de datos.

  • Usa las características de medios para cambiar estilos y evita vincular peticiones de red a ellas. Un fondo distinto para el modo oscuro suele poder resolverse con un solo recurso y propiedades personalizadas de CSS, o con el elemento <picture>, sin URLs por característica.
  • Sirve cualquier recurso condicionado por medios desde tu propio origen. Una petición a un host de terceros que difiere según la pantalla o la preferencia da a ese host una señal que tus visitantes nunca aceptaron compartir.
  • No registres qué recurso condicional descargó un visitante salvo que lo necesites. Si lo registras, indícalo en tu aviso de privacidad y conserva los datos poco tiempo.
  • Respeta la preferencia que las personas hayan elegido. El movimiento reducido, el contraste y los colores forzados son ajustes de accesibilidad, y el artículo sobre preferencias de media queries y control del usuario muestra cómo respetarlos manteniendo una forma visible de elegir la apariencia.

Estos hábitos cuestan poco y reducen la cantidad de datos de pantalla y preferencias que salen de la página.

Probar desde el lado del autor es sencillo. Abre el panel de red de tu navegador, cambia el esquema de color o el ajuste de movimiento reducido en el sistema operativo y observa qué peticiones cambian. Cualquier petición que varíe con una preferencia merece una segunda mirada: pregunta si el diseño la necesita, si el mismo resultado es posible con un solo recurso y si el host que la recibe te pertenece. Repasa esto cuando se añada una hoja de estilo o un widget de terceros, ya que un componente incrustado puede introducir peticiones condicionales que el resto del sitio nunca usó.

Los ajustes de accesibilidad merecen un cuidado especial en ambos lados. El movimiento reducido, el contraste alto y los colores forzados existen porque algunas personas no pueden usar cómodamente una página sin ellos. Una configuración de privacidad que los sustituye para parecerse a todos los demás puede dificultar el uso de los sitios a la persona que está al teclado, y un sitio que los ignora perjudica directamente a esas personas. Cuando el navegador con el que pruebas informa valores distintos de tus propios ajustes, recuerda que la diferencia se aplica solo a esa sesión y que tus preferencias reales siguen perteneciendo al navegador que usas cada día.

Qué cubre BotBrowser y qué deja fuera

La documentación de BotBrowser sobre CSS Signal Consistency describe las opciones implicadas. Un arranque básico carga un perfil, y el esquema de color y la fuente de la pantalla pueden fijarse de forma explícita.

chrome --bot-profile="path/to/profile.enc" \
       --bot-color-scheme=dark \
       --bot-screen=profile

--bot-color-scheme acepta light o dark. --bot-screen=profile usa las propiedades de pantalla definidas por el perfil, como la profundidad de color y las dimensiones, en lugar de los valores de la pantalla del equipo anfitrión. Ambos ajustes son opcionales.

Elige primero el perfil, porque los valores CSS de una sesión derivan de él. Un perfil describe un solo dispositivo, así que elige uno cuya plataforma y tipo de dispositivo coincidan con el trabajo que haces, y confirma el puntero y el hover con las comprobaciones anteriores. Cambiar después el esquema de color o la fuente de pantalla ajusta la presentación dentro de ese perfil. No convierte un perfil de escritorio en un teléfono.

BotBrowser puede mantener los valores de medios CSS y los valores de pantalla relacionados alineados con el perfil cargado: el esquema de color sigue al perfil y a --bot-color-scheme, y los valores de pantalla como la profundidad de color y las dimensiones siguen al perfil, de modo que una regla @media y matchMedia() informan los mismos valores coherentes con el perfil en lugar de los del equipo anfitrión. Esto te ayuda a confirmar que el camino de la hoja de estilo y el del script coinciden para un perfil dado, y que la respuesta no cambia entre sesiones. Los límites son igual de importantes. BotBrowser no puede controlar lo que solicita o registra la hoja de estilo de un sitio, no puede hacer que una sesión sea anónima ni imposible de vincular, y no sustituye tus propios ajustes de accesibilidad, como el movimiento reducido o el contraste.

Preguntas frecuentes

¿Una sola característica CSS identifica a una persona?

No. Las características individuales suelen aportar poca información; el riesgo procede de las combinaciones y de las contradicciones entre CSS y JavaScript.

¿Debo estandarizar todas las preferencias?

No necesariamente. Los valores fijos reducen la variación, pero pueden crear un grupo reconocible y sobrescribir ajustes de accesibilidad.

¿Qué debo registrar durante una prueba de coherencia?

Registra el perfil, las opciones de arranque explícitas, el resultado de CSS, el resultado del script y la fecha de la sesión para repetir la comparación.

Conclusión práctica

Para una comprobación repetible, selecciona un perfil coherente, fija el esquema de color o la fuente de pantalla cuando sea necesario, compara CSS y JavaScript en la misma página de prueba y repite la prueba en sesiones posteriores. Corrige las discrepancias antes de ajustar otras señales de huella, y recuerda que BotBrowser alinea valores, pero no controla la recopilación del sitio ni proporciona anonimato.

Fuentes públicas

#Css#fingerprinting#Media-Queries#privacidad

Este artículo forma parte de la guía: ¿Qué es la huella digital del navegador?

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.