Volver al Centro de conocimiento
Huella digital

Grupos de señales de CreepJS y cómo los combina

Una sonda sobre CreepJS: nueve patrones independientes forman una cadena de decisión ordenada, y uno solo se detecta comparando dos grupos.

BotBrowser Team

Documentación

Quieres la documentación estructurada de Huella digital?

Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.

BotBrowser permite reproducir un fixture del mismo origen autorizado bajo un perfil declarado y guardar un registro acotado de qué reportó cada grupo de sondeo, pero no puede hacer que un grupo coincida con otro que describe una superficie distinta, no puede ocultar un grupo que fue bloqueado en lugar de respondido, ni puede cambiar el orden en que una cadena de decisión nombra sus razones. Esta revisión lee CreepJS desde su código público, reproduce su decisión de nueve patrones y registra qué patrones puede activar un solo grupo, cuál necesita que dos grupos discrepen antes de dispararse, por qué el orden de los nueve decide qué razón se reporta, y qué pueden aportar los dos patrones de servidor desde dentro de una página.

Resumen

  • CreepJS ejecuta más de veinte grupos de sondeo y los reduce a una cadena de decisión de nueve bits, en orden fijo, junto a un resumen por grupo.
  • Un perfil limpio no activa ningún bit: la sonda imprime clean -> botHash=000000000 set=0 badBot=none.
  • Cuatro patrones los activa un solo grupo: un ámbito de Worker que mintió, una versión de características que no coincide, un Function.prototype.toString reemplazado y un ámbito de Worker bloqueado.
  • El ámbito bloqueado es la señal individual más barata, porque se dispara aunque nada haya mentido: worker-blocked -> botHash=000000100.
  • Un patrón necesita dos grupos: una plataforma de fuentes que discrepa del sistema que afirma el user agent del Worker.
  • Esa discrepancia entre grupos no tiene bit propio; alimenta el patrón de mentira extrema, así que font-vs-ua-feeds-extreme -> botHash=000010000 badBot=extremeLieCount.
  • El orden de los nueve decide la razón reportada: con cuatro bits activos la sonda imprime botHash=110100100 badBot=liedWorkerScope, e invertir el orden de entrada no cambia nada.
  • Dos patrones se calculan en un servidor, así que desde dentro de una página siempre valen cero: server-bits -> positions=6,8 always=00.

Contenido

El primer panel muestra un perfil limpio produciendo nueve bits en cero. El segundo muestra cuatro patrones de un solo grupo activando un bit en posiciones distintas. El tercero muestra una plataforma de fuentes que discrepa del user agent del Worker, lo que activa el bit de mentira extrema en lugar de uno propio. El cuarto muestra cuatro bits activos a la vez con la razón reportada tomada del más a la izquierda, y las dos posiciones de servidor siempre en cero.

Qué son los nueve bits y de dónde vienen

CreepJS no emite una puntuación. Ejecuta un conjunto de grupos de sondeo independientes, condensa la salida de cada grupo en un resumen propio y luego reduce nueve patrones concretos a una cadena de decisión ordenada. Los nueve vienen de grupos distintos, y eso es todo el diseño:

clean -> botHash=000000000 set=0 badBot=none

Nueve ceros para un navegador que no activó nada. Cada posición nombra un patrón tomado de una parte distinta de la página: el reporte del propio ámbito de Worker, la versión de plataforma que implica una medición de fuentes, si Function.prototype.toString se comporta todavía como un nativo, si una lista de características coincidió con la versión declarada, un recuento extremo de mentiras individuales, un exceso de huellas sueltas, si el ámbito de Worker se bloqueó, una puntuación de mezcla con la multitud, y un patrón de servidor.

Una discrepancia de plataforma entre dos grupos es el caso que por qué una señal rara no condena a un navegador puntúa distinto de una sola superficie delgada. Los resúmenes por grupo y la cadena de decisión responden preguntas distintas. Un resumen dice «estas dos ejecuciones del grupo canvas produjeron los mismos bytes», que es una afirmación de estabilidad sobre una superficie. La cadena dice «estas nueve condiciones con nombre fueron verdaderas», que es una afirmación sobre la página entera. Un perfil puede tener un resumen de canvas perfectamente estable y aun así activar un bit, porque el bit viene de otro grupo.

Esa separación conviene retenerla al leer cualquier informe de huellas. Un resumen de grupo estable se confunde a menudo con un buen resultado, y no es la misma afirmación. Estabilidad significa que el grupo es reproducible; no dice nada sobre si la salida de ese grupo coincide con la de otro.

Qué grupos pueden activar un bit solos

Cuatro de los nueve patrones los activa un grupo sin comparación alguna. La sonda ejecuta cada uno contra una base limpia:

worker-scope-lied -> botHash=100000000 set=1 badBot=liedWorkerScope
features-version-lied -> botHash=000100000 set=1 badBot=outsideFeaturesVersion
proxy-toString -> botHash=001000000 set=1 badBot=functionToStringHasProxy
worker-blocked -> botHash=000000100 set=1 badBot=workerScopeIsBlocked

Cada línea activa exactamente un bit, y cada bit está en una posición distinta, así que la cadena misma registra qué grupo habló. Un ámbito de Worker que reportó algo inconsistente activa la primera posición. Una lista de características que no coincidió con la versión declarada activa la cuarta. Un Function.prototype.toString que ya no se comporta como nativo activa la tercera. Un ámbito de Worker que no se pudo crear activa la séptima.

Un Worker que informa un valor distinto al de la página principal es una de las pocas señales que ningún cliente legítimo produce, y integridad de API entre realms lo registra en detalle. El caso del Worker bloqueado merece una pausa, porque se dispara sin mentira alguna. Nada reportó un valor equivocado; la página simplemente no consiguió que un ámbito de Worker respondiera. Eso lo convierte en la señal individual más barata de todo el conjunto: una página puede ser perfectamente consistente en cada superficie que sí expone y aun así activar este bit por no exponer una. Cualquier prueba que lea solo las superficies que respondieron lo pasará por alto.

La posición de Function.prototype.toString es la que una página puede influir más directamente, y el análisis de funciones nativas sustituidas y qué ve una lista de toString cubre qué ediciones sobreviven a esa comprobación y qué envoltorios la pasan. La cadena de aquí solo registra que el patrón se disparó; no dice qué edición lo causó.

Qué bit necesita que dos grupos discrepen

Un patrón no puede evaluarse desde un solo grupo, porque existe precisamente para comparar dos. La sonda le da un user agent y una plataforma de fuentes y registra qué decide la comparación:

cross:agree-win -> uaOS=WINDOWS fontOS=WINDOWS fontOSBad=false
cross:agree-mac -> uaOS=APPLE fontOS=APPLE fontOSBad=false
cross:disagree-ua-mac-font-win -> uaOS=APPLE fontOS=WINDOWS fontOSBad=true
cross:disagree-ua-win-font-mac -> uaOS=WINDOWS fontOS=APPLE fontOSBad=true
cross:android-with-mac-font -> uaOS=LINUX fontOS=APPLE fontOSBad=true

Cuando los dos grupos nombran la misma familia de plataforma, no se dispara nada. Cuando nombran familias distintas, la comparación se dispara en cualquiera de las dos direcciones, y también se dispara para un user agent de Android con una plataforma de fuentes que se lee como Apple. La dirección no importa, solo la discrepancia, que es lo que la convierte en una comprobación de coherencia y no en un umbral sobre un valor.

El caso de Android es el interesante para un despliegue. Un perfil que reporta un user agent de Android mientras sus mediciones de fuentes resuelven como familia Apple de escritorio activa este patrón aunque ninguno de los dos grupos parezca equivocado por separado. El user agent es una cadena plausible de Android y la plataforma de fuentes es una cadena plausible de Apple; simplemente no pueden ser verdaderas del mismo dispositivo.

Lo que el patrón hace con esa discrepancia es la parte fácil de pasar por alto:

font-vs-ua-feeds-extreme -> botHash=000010000 set=1 badBot=extremeLieCount

La discrepancia entre grupos no tiene bit propio. Alimenta la quinta posición, el patrón de mentira extrema, junto a un recuento absoluto de mentiras individuales. Así que un informe que dice que se activó el bit de mentira extrema puede significar que una página acumuló un número muy grande de inconsistencias pequeñas, o puede significar que bastó una discrepancia entre grupos. El bit no distingue esos dos casos, y quien lo lee tiene que volver a la salida por grupo para saber cuál fue.

Esa decisión de diseño es deliberada y tiene un coste. Meter una discrepancia cualitativa en el mismo bit que un recuento cuantitativo hace que la cadena pierda información que los grupos subyacentes todavía tienen. La cadena es un resumen, y el resumen es con pérdida de una manera concreta y documentada.

Por qué importa el orden de los bits

Las nueve posiciones no son equivalentes, porque la decisión reporta el primer bit activo como su razón. La sonda activa cuatro patrones a la vez y luego repite los mismos cuatro en otro orden de entrada:

many-bits -> botHash=110100100 set=4 badBot=liedWorkerScope
many-bits-reversed-input -> botHash=110100100 set=4 badBot=liedWorkerScope

Cuatro bits activos y la razón reportada es siempre la del más a la izquierda. El orden de entrada no cambia la cadena ni la razón, lo que significa que el orden vive en la lista fija y no en el orden en que los grupos terminaron. Una página que activa cuatro patrones solo recibe aviso de uno, y ese es el que está más a la izquierda.

La consecuencia práctica es que una sola razón reportada no significa un solo hallazgo. Un informe que nombra una razón junto a cuatro bits activos te está diciendo que hay cuatro, y elige mostrar el más a la izquierda. Quien lea solo la razón subestimará lo que la página hizo en realidad.

Dos de las nueve posiciones no pueden activarse desde dentro de una página:

server-bits -> positions=6,8 always=00

Las posiciones de huellas sueltas excesivas y de mezcla con la multitud se calculan donde se pueden comparar muchas sesiones, así que un navegador que se evalúa a sí mismo reporta cero en ambas haga lo que haga la página. Una ejecución del lado de la página cubre por tanto siete de los nueve patrones, y los dos que no cubre son los que necesitan una población en lugar de una sesión.

Las cadenas de un solo bit dicen lo mismo sobre la granularidad:

single:liedWorkerScope -> 100000000 position=1
single:functionToStringHasProxy -> 001000000 position=3
single:workerScopeIsBlocked -> 000000100 position=7

Tres hallazgos distintos, tres cadenas distintas, cada una con exactamente un bit. La cadena es precisa sobre qué patrón se disparó y silenciosa sobre cuán fuerte. Una página que activa la posición uno porque un ámbito de Worker reportó un valor equivocado y una que la activa porque el ámbito se contradijo en seis puntos producen la misma cadena.

El mapeo de versiones de Windows del que depende el patrón de versión de plataforma muestra por qué ese patrón también es grueso:

win-release:0.3.0 -> 8.1
win-release:8.0.0 -> 10 (1903|1909)
win-release:13.0.0 -> 11
win-release:15.0.0 -> 11

Cada versión de plataforma desde 13 en adelante se mapea a Windows 11, así que el patrón no distingue una compilación de Windows 11 de otra. Es una comprobación a nivel de familia, que es justo lo que la hace útil para detectar una falta de coincidencia e inútil para identificar una compilación.

Registrar una lectura de verificación cruzada

Una entrada redactada hace concretos los cuatro campos. Una ejecución que devolvió botHash=110100100 con badBot=liedWorkerScope se registra como la cadena más el commit más la salida por grupo del ámbito de Worker, de la lista de características, de la comprobación de Function.prototype.toString y de la medición de fuentes, y nombra las dos posiciones no evaluadas. Quien lo lea puede ver que se dispararon cuatro patrones, que la razón reportada es la posición uno, y que la comparación de fuentes frente a user agent contribuyó por la posición cinco en lugar de por un bit propio.

Una lectura de verificación cruzada sostiene una afirmación acotada: esta versión de la biblioteca, estos grupos, produjeron esta cadena de decisión. Cuatro campos la mantienen verificable:

  1. El commit de la biblioteca y la lista ordenada de patrones, porque las posiciones y su significado son código, y reordenar cambia en silencio qué razón se reporta.
  2. La salida por grupo junto a la cadena de decisión, porque la cadena junta una discrepancia cualitativa y un recuento cuantitativo en un bit y los grupos todavía guardan la distinción.
  3. Qué patrones se evaluaron y cuáles no, porque dos de los nueve necesitan una población y siempre valen cero en una ejecución del lado de la página.
  4. Los bits activos como cadena en lugar de un recuento, porque cuatro bits con una razón reportada y un bit solo son hallazgos distintos y un recuento no los separa.

Fuentes públicas

Conclusión

Lee un resultado de CreepJS como una cadena ordenada de patrones con nombre en lugar de una puntuación, porque la cadena dice qué grupo habló y la puntuación solo diría cuántos. Trata un ámbito de Worker bloqueado como un hallazgo por derecho propio aunque nada haya mentido, ya que es el patrón individual más barato y el más fácil de pasar por alto. Espera que el patrón de fuentes frente a user agent se dispare en cualquiera de las dos direcciones, y recuerda que alimenta el bit de mentira extrema en lugar de uno propio, así que la razón sola no distingue una discrepancia cualitativa de un recuento grande de otras pequeñas. Para la comprobación de integridad de la que depende una de las nueve posiciones, lee funciones nativas sustituidas y qué ve una lista de toString; para cómo se puntúa y se filtra una decisión construida con varias capas, lee por qué una señal rara no condena a un navegador.

#CreepJS#Grupos De Huellas#Verificación Cruzada#Señales Sin Cabeza#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.