- Desde Chrome 148,
Math.tanhde V8 llama astd::tanhdel host en lugar del fdlibm integrado, por lo que la misma entrada devuelve bits finales distintos en glibc de Linux,libsystem_mde macOS y UCRT de Windows Math.tanh(0.8)da0.6640367702678491en Linux,0.664036770267849en macOS y0.6640367702678489en Windows, lo que permite distinguir los tres sistemas operativos con una sola llamada; si el resultado no coincide con el sistema operativo que declara el User-Agent, la suplantación queda expuesta- La ruta de filtración varía según el motor: en
Math.*de V8 solotanhusa la biblioteca matemática del host, pero todas las funciones trigonométricas de CSS en Blink y algunas operaciones de Web Audio también pasan por bibliotecas específicas del sistema operativo - Si se perturban los valores de forma aleatoria, no coincidirán con ningún sistema operativo real y además se rompe la determinismo; por eso hay que reproducir bit a bit los coeficientes, tablas, reducción de rango y comportamiento FMA de la biblioteca objetivo, o mapear directamente el código original de UCRT
- Scrapfly compara en cada release 871,000 entradas contra Macs reales y Chrome para verificar que
Math.tanhy 7 funciones trigonométricas de CSS coincidan bit a bit, y ajusta no solo la precisión sino también las diferencias de arquitectura y el tiempo de ejecución al nivel de un navegador real
El sistema operativo que revela Math.tanh
- El resultado de
Math.tanh(0.8)cambia según la biblioteca matemática del host- glibc en Chrome para Linux:
0.6640367702678491 libsystem_men Chrome para macOS:0.664036770267849- UCRT en Chrome para Windows:
0.6640367702678489
- glibc en Chrome para Linux:
- Apple y glibc suelen diferir por 1 ULP en aproximadamente una cuarta parte de todas las entradas, mientras que Windows UCRT difiere de ambas bibliotecas en algunos puntos porcentuales de entradas
- ULP (unit in the last place) es la distancia entre números de punto flotante consecutivos representables para una magnitud dada; 1 ULP es la mínima diferencia que puede representar un
double
- ULP (unit in the last place) es la distancia entre números de punto flotante consecutivos representables para una magnitud dada; 1 ULP es la mínima diferencia que puede representar un
- Al medir Chrome 150 real en Linux, macOS 26 sobre Apple Silicon y Windows 11 mediante DevTools Protocol, la capacidad de clasificación cambia según la entrada
tanh(0.5)es igual en los tres sistemas operativos:0.46211715726000974, por lo que no sirve para deteccióntanh(0.7)solo difiere en Linux por 1 ULPtanh(0.8)es distinto en los tres sistemas operativos, con un rango total de 2 ULPtanh(0.9)solo difiere en Windows por 1 ULP
- En aproximadamente tres cuartas partes de las entradas, los tres sistemas operativos producen el mismo resultado, pero una sola entrada adecuada basta para obtener una firma por sistema operativo
- Si se declara macOS pero se devuelven los bits matemáticos de Linux, el resultado de
Math.tanhcontradice al User-Agent
El cambio ocurrido en Chrome 148
- Hasta Chrome 147, V8 calculaba
Math.tanhcon un port integrado de fdlibm, una implementación matemática portable, por lo que devolvía los mismos bits en todos los sistemas operativos - El commit de V8
c1486295ae5reemplazó la implementación integrada porstd::tanhde la plataforma- Este cambio se incluyó por primera vez en V8 14.8.57 y Chrome 148
- Chrome 148, 149 y 150 exponen las diferencias del
libmdel host, pero Chrome 147 y anteriores no filtran el sistema operativo por esta ruta
- IEEE 754 define cómo se almacena un
double, pero no exige que funciones trascendentales comosin,cos,tanhoexpestén necesariamente redondeadas de forma correcta - La biblioteca matemática (libm) de cada sistema operativo equilibra rendimiento y error en ULP usando distintos coeficientes de polinomios de aproximación minimax, tablas de consulta y constantes de reducción de rango
- Linux usa glibc
- macOS usa Apple
libsystem_m - Windows usa
ucrtbase.dllde UCRT
- Un detector no necesita analizar la operación matemática en sí: puede comparar el valor contra una tabla de resultados por entrada de Chrome real
Cuatro trampas que dificultan la reproducción
-
Solo se filtran algunas funciones de V8
- V8 enlaza estáticamente la mayoría de sus implementaciones matemáticas, así que produce el mismo resultado sin importar el sistema operativo
Math.exp,Math.pow,Math.atany otras usan la implementación integrada de llvm-libcMath.sinyMath.cosusan rutinas integradasdbl-64originadas en glibc- Desde Chrome 148, solo
Math.tanh, que usastd::tanhde la plataforma, filtra el sistema operativo dentro deMath.* - Si se falsifican como si fueran del sistema operativo objetivo funciones que no filtran, se rompe la estructura real de llamadas de V8; incluso puede comprobarse la asimetría de que solo
tanhsea diferente
-
JavaScript y CSS usan rutas distintas
sin(),cos()yatan2()de CSS no comparten código conMath.sinde JavaScript- El motor de layout Blink reduce los ángulos en grados y luego llama a
std::sinde la plataforma, entre otras funciones, sobre el valor reducido - El resultado difiere del cálculo directo con entrada en radianes, y las 7 funciones trigonométricas de CSS filtran el sistema operativo a través del
libmdel host - Para reproducir bit a bit hay que incluir no solo la función matemática final, sino también la reducción de rango en grados y la conversión entre radianes y grados
-
Dentro de macOS hay dos bibliotecas distintas
- En Apple Silicon conviven el
libsystem_mescalar y las rutinas vectorialesvvsin,vvtanhde Accelerate, y ambas implementaciones no son iguales - En un millón de entradas, los resultados difirieron entre 10% y 89% según la función
cos(0)es exactamente1.0en la implementación escalar- En Accelerate devuelve
0.9999999999999999 - Se mide Chrome en un Mac real mediante el protocolo de depuración para distinguir qué biblioteca se usa en cada punto de llamada
Math.tanh, las funciones trigonométricas de CSS y las funciones trascendentales por muestra del compresor de audio usan ellibsystem_mescalar- El DSP de Web Audio en Mac, FFT, matemáticas vectoriales y filtros biquad usan Accelerate
- Entre las rutas relacionadas de Chromium están
fft_frame_mac.cc,vector_math_mac.h,biquad.ccyBUILDFLAG(IS_MAC) - Si se elige una biblioteca de Apple que no corresponde al punto de llamada, muchas entradas pueden quedar desfasadas por 1 ULP
- En Apple Silicon conviven el
-
La arquitectura de CPU también interviene en el resultado
- ARM y x86 muestran diferencias en fused multiply-add (FMA) y en la propagación del signo de NaN
- Aunque el procedimiento matemático sea correcto, si el compilador fusiona una multiplicación y una suma solo en una arquitectura, los bits del resultado cambian
Rutas de filtración por motor y funcionalidad
Math.*de V8 en JavaScript usa casi siempre implementaciones integradas; el único punto conectado allibmdel host esMath.tanhsin,cos,tan,asin,acos,atan,atan2,exp,log,log2,log10ypowusan implementaciones integradas de V8sqrt,absy las cuatro operaciones aritméticas son operaciones de hardware
- Las funciones matemáticas de
calc()en CSS hacen que Blink llame directamente a la biblioteca de la plataformasin,cos,tan,asin,acos,atan,atan2,exp,log,log2,log10ypowusan ellibmdel host- En CSS no existe una ruta correspondiente para
tanh
- Web Audio mezcla varias implementaciones según el punto de llamada
- En Mac, la FFT del oscilador, suma, multiplicación y escalado vectoriales, y FFT usan
vDSPde Accelerate - Funciones trascendentales por muestra en DynamicsCompressor, como
sin,exp,log10fypowf, usan ellibsystem_mescalar - Un solo grafo de audio puede atravesar tres bibliotecas: matemáticas integradas de V8, biblioteca escalar y Accelerate
- En Mac, la FFT del oscilador, suma, multiplicación y escalado vectoriales, y FFT usan
- WebAssembly no tiene instrucciones para funciones trascendentales
- El resultado de
siny similares queda determinado por ellibmincluido en el módulo - Aritmética como
f64.sqrtyf64.mulse ejecuta en hardware, por lo que es igual entre sistemas operativos - Los ejes de fingerprinting restantes son la normalización de NaN entre ARM y x86, y algunas diferencias de redondeo en SIMD
- El resultado de
- Las señales de detección se concentran en
Math.tanh, todas las funciones trigonométricas de CSS y Web Audio- La FFT de Accelerate en Web Audio revela la arquitectura de CPU
- El
libsystem_mescalar del compresor revela el sistema operativo
Reproducir con exactitud en lugar de perturbar los valores
-
Por qué falla el ruido
- Si se agrega ruido al resultado, puede no coincidir con ningún valor real de sistema operativo en la tabla de referencia
- Si el valor aleatorio cambia en cada llamada, se rompe la determinismo, y ese fenómeno se convierte en otra señal de detección
- El objetivo no es obtener un valor parecido, sino un resultado bit a bit idéntico al que devuelve el sistema operativo declarado
-
Restaurar todos los elementos del algoritmo objetivo
- Se recuperan del
libmobjetivo los coeficientes de aproximación minimax, tablas de exponentes y constantes de reducción de rango, y se trasladan a código C portable - Incluso las entradas que la biblioteca objetivo redondea en la dirección incorrecta deben coincidir exactamente
- La reproducción de
sinde Apple usa el patrón exacto de bits de los coeficientes extraídos delibsystem_my llamadas explícitas afma() - Si los coeficientes se pasan a decimal, pueden volver a redondearse durante la transcripción, por lo que se preservan como valores de punto flotante hexadecimales
- Cada multiplicación-suma que Apple fusiona también se fusiona explícitamente en el código
- Se recuperan del
-
Fijar FMA de forma determinista
- Se compila con
-ffp-contract=offpara impedir que el compilador agregue o elimine FMA arbitrariamente - Solo los
fma()explícitos del código se ejecutan en las mismas posiciones que Apple, por lo que se obtienen los mismos bits incluso al imitar ARM en un servidor x86 - El FMA de hardware y un FMA de software correctamente redondeado devuelven los mismos bits
- Se compila con
Uso del código original de Windows UCRT
- Windows UCRT usa la misma ISA x86-64 que un servidor Linux y es independiente de posición, por lo que se puede mapear el
ucrtbase.dllreal en memoria en tiempo de ejecución y llamar directamente a los exports de funciones matemáticas - Como se ejecuta el código original, se obtienen los bits reales de UCRT sin ingeniería inversa adicional del algoritmo matemático
- Hay que manejar la diferencia entre la ABI System V de Linux y la ABI x64 de Windows
- En Windows x64, el callee usa un shadow space de 32 bytes encima de la dirección de retorno
- El conjunto de registros preservados por el callee también difiere de System V
- Si el puntero a función no se declara como
ms_abi, las escrituras en el shadow space corrompen el stack frame de clang y la llamada indirecta puede saltar a una dirección incorrecta
- El código del DLL mapeado no es un destino de llamada indirecta registrado en CFI
- En producción,
-fsanitize=cfi-icallpuede provocar una trampa#UDySIGILLen cada llamada - El wrapper que llama al puntero a función necesita
clang::no_sanitize("cfi-icall")
- En producción,
- Las funciones matemáticas de UCRT leen al inicio un flag de despacho de CPU con
mov eax, [rip+disp32]para elegir la ruta escalar o FMA/AVX2- En un DLL recién mapeado, el flag es 0, así que elige la ruta escalar lenta
- El resultado de esa ruta difiere en bits del resultado de sistemas Windows modernos
- Hay que encontrar la dirección del flag en el prólogo de
tanhy forzar la ruta FMA antes de la primera llamada para coincidir bit a bit con Windows real
Puntos de parcheo y restricciones de rendimiento
- Se engancha el único cuello de botella donde el motor llama a
libm, y se elige la ruta según el sistema operativo que declara el navegador- Si declara Linux, se conserva glibc
- Si declara macOS, se usa la implementación de reproducción de Apple
- Aunque el resultado sea exacto, puede detectarse si el tiempo de ejecución difiere del de un navegador real
- La primera compilación tenía una línea base x86 por defecto más antigua que FMA de hardware, por lo que todos los
fma()se degradaban a llamadas de software y era entre 2.5 y 6 veces más lenta que la nativa - Al comparar la proporción de tiempos en bucles de
Math.tanhyMath.sin, pueden revelarse patrones de rendimiento inexistentes en un navegador real - Al habilitar FMA de hardware, cada operación fusionada se convirtió en una sola instrucción y aceleró alrededor de 6 veces; además, quedó más rápida que glibc manteniendo idénticos los bits del resultado
Validación con 871,000 entradas
- El harness de validación ejecuta en cada release 871,000 entradas que cubren todas las ramas y dominios
- grilla densa de entradas
- límites de intervalos
- subnormales
- cero con signo
- infinito
- NaN
- Se usan dos tipos de entornos reales como valores de referencia
- Un Mac real calcula en todas las entradas los resultados escalares y de Accelerate por separado para identificar dónde divergen las dos implementaciones
- Chrome en un Mac real se controla mediante el protocolo de depuración para recolectar resultados de precisión completa de
Math.tanhy de todas las funciones trigonométricas de CSS
Math.tanhysin,cos,tan,asin,acos,atan,atan2de CSS coinciden bit a bit con Chrome real en Mac- También se verifica que la implementación de reproducción se comporte igual que el código máquina real dentro del binario distribuido
- Hay que igualar incluso el posprocesamiento del navegador en los límites del dominio
- En un Mac real, CSS
asin(2)está fuera del dominio, por lo que se convierte en NaN, y CSS limita NaN a 0; el valor final es0 - Una implementación de reproducción simple podría devolver erróneamente 90 grados
- En un Mac real, CSS
Por qué las matemáticas importan en la suplantación de navegadores
- Los resultados matemáticos pueden comprobarse de forma determinista y barata, pero para suplantarlos con precisión hay que conocer el interior del
libmdel proveedor y las rutas de llamada de cada motor - Para coincidir con un navegador real hay que saber qué biblioteca matemática eligen V8, Blink y Web Audio en cada punto de llamada, y ajustar el último bit, el comportamiento por arquitectura y hasta el tiempo de ejecución
- Scrapium de Scrapfly está configurado para que, cuando se le pide presentarse como macOS, incluso los bits de redondeo del coseno coincidan con el tráfico real de macOS
1 comentarios
Comentarios en Hacker News
La explicación de que el resultado de llamar una vez a
tanhcon la entrada de la derecha se vuelve una firma por sistema operativo pasa por alto que también podría identificar un rango de versiones del navegadorLa mayoría no falsifica el sistema operativo del User-Agent, y el fingerprinting se interesa más por combinaciones de rasgos semiúnicos que por el sistema operativo en sí. El hallazgo es interesante, pero el texto está demasiado escrito por LLM y eso le quita credibilidad.
Así pueden pasar más fácilmente la detección de bots y vender a clientes datos recolectados de otros sitios web.
El hecho de que fue escrito con LLM se reveló en el artículo y en el blog; no se ocultó ni se fingió ser humano. Por falta de tiempo, de otro modo no habrían podido publicar el artículo, y están dispuestos a asumir esa decisión.
El navegador sigue añadiendo funciones y corrigiendo errores, y la mayoría de ellos puede detectarse con JavaScript.
Es una estrategia inteligente: analizar con IA todas las técnicas de fingerprinting y publicarlas, y tras la polémica empujar a los navegadores a bloquearlas, para que su negocio de scraping gane más dinero
Si no existieran empresas así, el fingerprinting del navegador no estaría tan extendido como ahora y internet sería mejor. Preferiría más bien textos del lado opuesto con intereses claros, como fingerprint.js.
Hay otra razón más para impulsar las funciones trascendentales con redondeo correcto
Hace poco me enteré de que este problema en la práctica ya está resuelto. Vean la segunda ponencia magistral de https://arith2026.org/program.html.
libmcon redondeo correcto son excelentes, pero no deben tener un peor caso de rendimiento terrible, como pasó conpowde glibc en el pasadoSe podría mejorar el peor caso vectorizando manualmente con SLP la ruta alternativa de alta precisión usada cerca del umbral de redondeo, pero para la mayoría de usos ya es suficiente. Sorprende que los motores de JavaScript no sigan usando
fdlibm, recomendado por la especificación ECMAScript, y siMath.tanhes una ruta crítica en JavaScript, sería un código bastante extraño.En ingeniería, el punto fijo se usaba mucho porque funciona en hardware mucho más simple y los errores pueden modelarse matemáticamente con facilidad. El punto flotante IEEE 754 también es teóricamente dudoso, y cuando se pierde precisión, a veces enteros más pequeños que la mantisa —es decir, enteros de menos de 24 bits— pueden ser mejores que flotantes de 32 bits.
Ojalá esta técnica se agregue a https://coveryourtracks.eff.org/ para poder ver qué tan únicos son los resultados de mis funciones matemáticas dentro de una población más grande.
No sé si sea cierto, pero creo que las señales que usa coveryourtracks.eff.org son como 25.
El texto se nota escrito por Claude.
Al hacer clic en el enlace de Claude, se envía el prompt
summarize+this+article+and+explain+how+scrapfly+helps+me+scrape+any+website+at+scale+and+bypass+anti-bot+systems+for+my+use+case:+[https://scrapfly.dev/posts/browser-math-os-fingerprint/](<https://scrapfly.dev/posts/browser-math-os-fingerprint/>).Tor Browser y Mullvad Browser terminaron renunciando a ocultar el sistema operativo, pero quizá no debieron hacerlo
Parece que hay demasiadas rutas de fingerprinting.
Dentro y fuera del navegador ocurren demasiadas diferencias de comportamiento según el sistema operativo como para cubrirlas todas. Aunque se bloquee la extracción de canvas o se agregue ruido, aún pueden filtrarse diferencias de renderizado, y desarrolladores de Tor Browser también confirmaron que no pueden ocultar del todo ni siquiera la diferencia entre X11 y Wayland, mucho menos entre sistemas operativos completamente distintos. https://forum.torproject.org/t/linux-is-it-alright-to-run-th...
navigator.platform, así que es muy fácil detectar entornos que no son Windows.Basta con poner este código en tu plugin favorito de inyección de JavaScript:
let oldTanh = Math.tanh; Math.tanh = x => oldTanh(x) + Math.random()/10000000;Math.tanh = Math.random;glibc reciente usa el
tanhcon redondeo correcto de CORE-MATH, así que devuelve resultados distintos a los valores citados en el artículoAún no está claro si otras funciones trascendentales pueden implementar redondeo correcto con un rendimiento razonable, así que cada función deja su propio fingerprint único.
Chrome tiene cientos de MB solo en código ejecutable, así que pensé que habría enlazado estáticamente al menos la mitad de las bibliotecas de espacio de usuario
Además, creía que
tanhno era una llamada a función sino una operación integrada que el JIT de JavaScript emitía como instrucción de CPU, así que resulta raro que para una operación matemática haya que ramificarse mediante la funcióndlsym(). Las propias instrucciones de CPU también pueden usarse para fingerprinting.El microcódigo no obtiene ventajas como la predicción de saltos, así que en la práctica es más lento que una implementación en software.
Dudo que se pueda ganar esta pelea
Si se ejecutan suficientes funciones, parece posible estimar no solo el sistema operativo y el modelo exacto, sino incluso otras cargas que estén corriendo en la misma máquina, combinando proporciones de tiempo de ejecución y resultados de redondeo. Más que bloquearlo por completo, solo parece posible hacerlo un poco más difícil
Al final la sociedad y la ley tienen que ponerse al día. Así como una cerradura no impide totalmente una intrusión pero se complementa con la condena social y el castigo penal, habría que ilegalizar este tipo de rastreo personal y rechazar socialmente a las empresas y empleados que se benefician de él.
En lugares como Rusia, Myanmar o Corea del Norte, el Estado de derecho no funciona, e incluso las autoridades locales pueden proteger activamente a criminales que estafan a extranjeros, así que la analogía de la cerradura no se sostiene.