- Ab Chrome 148 ruft V8s
Math.tanhstatt des eingebauten fdlibm diestd::tanhdes Hosts auf. Dadurch liefern dieselben Eingaben unter Linux mit glibc, macOS mitlibsystem_mund Windows mit UCRT unterschiedliche letzte Bits zurück Math.tanh(0.8)ergibt unter Linux0.6640367702678491, unter macOS0.664036770267849und unter Windows0.6640367702678489; damit lassen sich die drei OS mit einem einzigen Aufruf unterscheiden, und wenn das Ergebnis nicht zum vom User-Agent behaupteten OS passt, wird die Tarnung sichtbar- Je nach Engine unterscheidet sich der Leckpfad: In V8s
Math.*nutzt nurtanhdie Mathebibliothek des Hosts, während in Blink alle trigonometrischen CSS-Funktionen und einige Web-Audio-Operationen ebenfalls über OS-spezifische Bibliotheken laufen - Werte zufällig zu verändern passt zu keinem realen OS und zerstört außerdem die Deterministik; daher muss man Koeffizienten, Tabellen, Range Reduction und FMA-Verhalten der Zielbibliothek bitgenau reproduzieren oder den ursprünglichen UCRT-Code direkt mappen
- Scrapfly gleicht pro Release 871.000 Eingaben gegen echte Macs und Chrome ab, verifiziert die Bit-Übereinstimmung von
Math.tanhund sieben CSS-Trigonometriefunktionen und stimmt nicht nur die Genauigkeit, sondern auch Architekturunterschiede und Laufzeit auf das Niveau echter Browser ab
Das OS, das Math.tanh offenlegt
- Das Ergebnis von
Math.tanh(0.8)hängt von der Mathebibliothek des Hosts ab- glibc in Linux Chrome:
0.6640367702678491 libsystem_min macOS Chrome:0.664036770267849- UCRT in Windows Chrome:
0.6640367702678489
- glibc in Linux Chrome:
- Apple und glibc unterscheiden sich bei etwa einem Viertel aller Eingaben meist um 1 ULP; Windows UCRT weicht bei einigen Prozent der Eingaben von beiden Bibliotheken ab
- ULP (unit in the last place) ist der Abstand zwischen zwei aufeinanderfolgenden darstellbaren Gleitkommazahlen einer bestimmten Größenordnung; 1 ULP ist die kleinste Differenz, die ein
doubledarstellen kann
- ULP (unit in the last place) ist der Abstand zwischen zwei aufeinanderfolgenden darstellbaren Gleitkommazahlen einer bestimmten Größenordnung; 1 ULP ist die kleinste Differenz, die ein
- Misst man Chrome 150 unter Linux, macOS 26 auf Apple Silicon und Windows 11 über das DevTools Protocol, unterscheidet sich die Klassifizierungsstärke je nach Eingabe
tanh(0.5)ist auf allen drei OS gleich:0.46211715726000974und eignet sich daher nicht zur Erkennungtanh(0.7)unterscheidet nur Linux um 1 ULPtanh(0.8)ist auf allen drei OS verschieden; die gesamte Spanne beträgt 2 ULPtanh(0.9)unterscheidet nur Windows um 1 ULP
- Bei etwa drei Vierteln der Eingaben liefern die drei OS dasselbe Ergebnis, doch eine passende einzelne Eingabe reicht aus, um eine OS-spezifische Signatur zu erhalten
- Wenn ein Browser macOS behauptet, aber Linux-Mathebits zurückgibt, widerspricht das
Math.tanh-Ergebnis dem User-Agent
Die Änderung in Chrome 148
- Bis Chrome 147 enthielt V8 einen Port von fdlibm, einer portablen Matheimplementierung, und berechnete damit
Math.tanh; deshalb wurden auf allen OS dieselben Bits zurückgegeben - Der V8-Commit
c1486295ae5ersetzte die eingebaute Implementierung durch diestd::tanhder Plattform- Diese Änderung ist erstmals in V8 14.8.57 und Chrome 148 enthalten
- Chrome 148, 149 und 150 legen Unterschiede der Host-
libmoffen, während Chrome 147 und älter auf diesem Weg kein OS leaken
- IEEE 754 definiert die Speicherung von
double, verlangt aber nicht, dass transzendente Funktionen wiesin,cos,tanhoderexpzwingend korrekt gerundet werden - Die Mathebibliotheken (libm) der einzelnen OS treffen unterschiedliche Kompromisse zwischen Performance und ULP-Fehlern und verwenden verschiedene Minimax-Approximationspolynome, Lookup-Tabellen und Konstanten für die Range Reduction
- Linux nutzt glibc
- macOS nutzt Apples
libsystem_m - Windows nutzt
ucrtbase.dllder UCRT
- Ein Detektor muss die mathematische Operation selbst nicht analysieren, sondern kann Werte mit Ergebnistabellen pro Eingabe aus echtem Chrome vergleichen
Vier Fallstricke, die eine Reproduktion erschweren
-
Nur einige V8-Funktionen leaken
- V8 linkt die meisten Matheimplementierungen statisch, sodass sie unabhängig vom OS dieselben Ergebnisse liefern
Math.exp,Math.pow,Math.atanund andere verwenden die eingebaute llvm-libc-ImplementierungMath.sinundMath.cosverwenden eingebaute, von glibc abgeleitetedbl-64-Routinen- Seit Chrome 148 leakt innerhalb von
Math.*nurMath.tanh, das die Plattform-std::tanhnutzt, das OS - Wenn man auch nicht leakende Funktionen wie das Ziel-OS fälscht, widerspricht das der realen Aufrufstruktur von V8; auch die Asymmetrie, dass nur
tanhabweicht, lässt sich prüfen
-
JavaScript und CSS verwenden unterschiedliche Pfade
- CSS-
sin(),cos()undatan2()teilen keinen Code mit JavaScriptsMath.sin - Die Blink-Layout-Engine reduziert Winkel in Grad und ruft dann auf dem reduzierten Wert Plattformfunktionen wie
std::sinauf - Das unterscheidet sich vom Ergebnis einer direkten Berechnung mit Radiant-Eingaben, und alle sieben CSS-Trigonometriefunktionen leaken über die Host-
libmdas OS - Für eine bitgenaue Reproduktion müssen nicht nur die finalen Mathefunktionen, sondern auch die Range Reduction in Grad sowie die Umrechnung zwischen Radiant und Grad berücksichtigt werden
- CSS-
-
Innerhalb von macOS gibt es zwei unterschiedliche Bibliotheken
- Auf Apple Silicon gibt es sowohl die skalare
libsystem_mals auch Vektorroutinen von Accelerate wievvsinundvvtanh; beide Implementierungen sind nicht identisch - Bei einer Million Eingaben unterschieden sich je nach Funktion 10 bis 89 % der Ergebnisse
cos(0)ist in der skalaren Implementierung exakt1.0- Accelerate gibt
0.9999999999999999zurück - Durch Messungen von echtem Chrome auf einem Mac über das Debugging-Protokoll wird pro Aufrufstelle die verwendete Bibliothek unterschieden
Math.tanh, CSS-Trigonometriefunktionen und die sampleweisen transzendenten Funktionen des Audiokompressors verwenden die skalarelibsystem_m- Web-Audio-DSP, FFT, Vektormathematik und Biquad-Filter auf dem Mac verwenden Accelerate
- Relevante Chromium-Pfade enthalten
fft_frame_mac.cc,vector_math_mac.h,biquad.ccsowieBUILDFLAG(IS_MAC) - Wählt man die falsche Apple-Bibliothek für eine Aufrufstelle, kann man bei den meisten Eingaben um 1 ULP danebenliegen
- Auf Apple Silicon gibt es sowohl die skalare
-
Auch die CPU-Architektur beeinflusst das Ergebnis
- ARM und x86 unterscheiden sich bei Fused Multiply-Add (FMA) und bei der Propagation von NaN-Vorzeichen
- Selbst wenn das mathematische Verfahren stimmt, können sich die Ergebnisbits ändern, wenn der Compiler Multiplikation und Addition nur auf einer Architektur fusioniert
Leckpfade nach Engine und Funktion
- V8s JavaScript-
Math.*verwendet fast vollständig eingebaute Implementierungen; der einzige Verbindungspunkt zur Host-libmistMath.tanhsin,cos,tan,asin,acos,atan,atan2,exp,log,log2,log10,powverwenden V8s eingebaute Implementierungensqrt,absund die vier Grundrechenarten sind Hardwareoperationen
- Die Mathefunktionen von CSS
calc()rufen in Blink direkt Plattformbibliotheken aufsin,cos,tan,asin,acos,atan,atan2,exp,log,log2,log10,powverwenden die Host-libm- In CSS gibt es keinen entsprechenden
tanh-Pfad
- Web Audio mischt je nach Aufrufstelle mehrere Implementierungen
- Oszillator-FFT, Vektoraddition, -multiplikation, -skalierung und FFT auf dem Mac verwenden
vDSPvon Accelerate - Sampleweise transzendente Funktionen im DynamicsCompressor wie
sin,exp,log10f,powfverwenden die skalarelibsystem_m - Ein einzelner Audio-Graph kann sich über drei Bibliotheken erstrecken: V8s eingebaute Mathematik, die skalare Bibliothek und Accelerate
- Oszillator-FFT, Vektoraddition, -multiplikation, -skalierung und FFT auf dem Mac verwenden
- WebAssembly hat keine Befehle für transzendente Funktionen
- Ergebnisse von
sinund ähnlichen Funktionen hängen von der im Modul enthaltenenlibmab - Arithmetik wie
f64.sqrtundf64.mulläuft auf der Hardware und ist daher OS-übergreifend gleich - Als verbleibende Fingerprinting-Achsen bleiben NaN-Normalisierung zwischen ARM und x86 sowie einige SIMD-Rundungsunterschiede
- Ergebnisse von
- Die Erkennungssignale konzentrieren sich auf
Math.tanh, alle CSS-Trigonometriefunktionen und Web Audio- Accelerate-FFT in Web Audio legt die CPU-Architektur offen
- Die skalare
libsystem_mdes Kompressors legt das OS offen
Exakt reproduzieren statt Werte zu verwackeln
-
Warum Rauschen scheitert
- Fügt man Ergebnissen Rauschen hinzu, passen sie möglicherweise zu keinem realen OS-Wert in der Referenztabelle
- Wenn sich Zufallswerte bei jedem Aufruf ändern, geht die Deterministik verloren, und dieses Verhalten wird selbst zu einem eigenen Erkennungssignal
- Ziel sind nicht ähnliche Werte, sondern Ergebnisse, die bitgenau den Rückgaben des behaupteten OS entsprechen
-
Alle Bestandteile des Zielalgorithmus wiederherstellen
- Aus der Ziel-
libmwerden Minimax-Approximationskoeffizienten, Exponententabellen und Konstanten für die Range Reduction rekonstruiert und in portablen C-Code übertragen - Auch Eingaben, bei denen die Zielbibliothek in die falsche Richtung rundet, müssen exakt übereinstimmen
- Die Apple-
sin-Reproduktion nutzt das exakte Bitmuster der auslibsystem_mextrahierten Koeffizienten und explizitefma()-Aufrufe - Überträgt man Koeffizienten als Dezimalzahlen, können sie beim Transkribieren erneut gerundet werden; daher werden sie als hexadezimale Gleitkommawerte bewahrt
- Jede Multiplikation-Addition, die Apple fusioniert, wird auch im Code explizit fusioniert
- Aus der Ziel-
-
FMA deterministisch festnageln
- Mit
-ffp-contract=offwird kompiliert, damit der Compiler nicht eigenmächtig FMA hinzufügt oder entfernt - Nur die im Code explizit angegebenen
fma()-Aufrufe laufen an denselben Stellen wie bei Apple; dadurch erhält man dieselben Bits, auch wenn man ARM nachahmt, aber auf einem x86-Server ausführt - Hardware-FMA und korrekt gerundete Software-FMA geben dieselben Bits zurück
- Mit
Originalcode der Windows-UCRT verwenden
- Die Windows-UCRT nutzt dieselbe x86-64-ISA wie Linux-Server und ist positionsunabhängig, sodass die tatsächliche
ucrtbase.dllin den Laufzeitspeicher gemappt und ihre exportierten Mathefunktionen direkt aufgerufen werden können - Da der Originalcode ausgeführt wird, erhält man die echten UCRT-Bits, ohne den separaten Mathealgorithmus reverse-engineeren zu müssen
- Unterschiede zwischen Linux System V ABI und Windows x64 ABI müssen behandelt werden
- Unter Windows x64 nutzt der Callee 32 Byte shadow space oberhalb der Rücksprungadresse
- Auch die Menge der callee-saved Register unterscheidet sich von System V
- Wird der Funktionszeiger nicht als
ms_abideklariert, beschädigen Schreibvorgänge in den shadow space den clang-Stackframe, und der indirekte Aufruf springt an eine falsche Adresse
- Der gemappte DLL-Code ist kein für CFI registriertes Ziel indirekter Aufrufe
- In Produktion kann
-fsanitize=cfi-icallbei jedem Aufruf eine#UD-Trap undSIGILLauslösen - Wrapper, die den Funktionszeiger aufrufen, benötigen
clang::no_sanitize("cfi-icall")
- In Produktion kann
- UCRT-Mathefunktionen lesen am Anfang mit
mov eax, [rip+disp32]CPU-Dispatch-Flags und wählen damit den skalaren oder den FMA/AVX2-Pfad- In einer frisch gemappten DLL ist das Flag 0, sodass der langsame skalare Pfad gewählt wird
- Die Ergebnisse dieses Pfads unterscheiden sich in den Bits von denen aktueller Windows-Systeme
- Im
tanh-Prolog muss die Flag-Adresse gefunden und vor dem ersten Aufruf der FMA-Pfad erzwungen werden, damit die Bits exakt mit echtem Windows übereinstimmen
Patch-Position und Performance-Vorgaben
- Man hookt den einzelnen Engpass, an dem die Engine
libmaufruft, und wählt den Pfad je nach vom Browser behauptetem OS- Wird Linux behauptet, bleibt glibc erhalten
- Wird macOS behauptet, nutzt man die Apple-Reimplementierung
- Auch wenn die Ergebnisse korrekt sind, ist es erkennbar, wenn die Laufzeit von einem echten Browser abweicht
- Der erste Build hatte eine grundlegende x86-Baseline, die älter als Hardware-FMA war, und senkte alle
fma()auf Softwareaufrufe ab; er war 2,5- bis 6-mal langsamer als nativ - Vergleicht man das Zeitverhältnis von
Math.tanh- undMath.sin-Schleifen, können Performance-Muster sichtbar werden, die in echten Browsern nicht vorkommen - Nach Aktivierung von Hardware-FMA wurde jede fusionierte Operation zu einem einzelnen Befehl, etwa sechsmal schneller; zugleich blieben die Ergebnisbits identisch und waren sogar schneller als glibc
Verifikation mit 871.000 Eingaben
- Der Verifikations-Harness führt pro Release 871.000 Eingaben über alle Branches und Definitionsbereiche hinweg aus
- Dichte Eingabegitter
- Intervallgrenzen
- Subnormalzahlen
- Vorzeichenbehaftete Nullen
- Unendlichkeiten
- NaN
- Zwei Arten realer Umgebungen dienen als Referenzwerte
- Ein echter Mac berechnet für alle Eingaben jeweils die skalaren und Accelerate-Ergebnisse, um die Punkte zu ermitteln, an denen sich beide Implementierungen unterscheiden
- Echtes Chrome auf einem Mac wird über das Debugging-Protokoll gesteuert, um Ergebnisse in voller Präzision für
Math.tanhund alle CSS-Trigonometriefunktionen zu sammeln
Math.tanhsowie CSS-sin,cos,tan,asin,acos,atan,atan2stimmen bitgenau mit echtem Mac Chrome überein- Außerdem wird verifiziert, dass sich die Reimplementierung genauso verhält wie der tatsächliche Maschinencode im ausgelieferten Binary
- Auch Browser-Postprocessing an Definitionsbereichsgrenzen muss passen
- Auf einem echten Mac liegt CSS
asin(2)außerhalb des Definitionsbereichs, wird daher zu NaN, und CSS begrenzt NaN auf 0; der Endwert ist also0 - Eine einfache Reimplementierung könnte dies fälschlich als 90 Grad zurückgeben
- Auf einem echten Mac liegt CSS
Warum Mathematik bei Browser-Tarnung wichtig ist
- Matheergebnisse lassen sich deterministisch und günstig prüfen, sind aber nur korrekt zu tarnen, wenn man die Interna der Vendor-
libmund die aufrufstellenspezifischen Pfade der Engine kennt - Um mit echten Browsern übereinzustimmen, muss man verstehen, welche Mathebibliothek V8, Blink und Web Audio an jeder Aufrufstelle wählen, und außerdem das letzte Bit, architekturspezifisches Verhalten und die Laufzeit angleichen
- Scrapflys Scrapium wird so konfiguriert, dass bei einer Anforderung, macOS auszuweisen, selbst die Rundungsbits von Cosinus zu echtem macOS-Traffic passen
1 Kommentare
Meinungen auf Hacker News
Die Erklärung, dass ein einzelner Aufruf von
tanhmit der richtigen Eingabe zu einer betriebssystemspezifischen Signatur wird, übersieht die Möglichkeit, den Bereich der Browser-Versionen zu identifizieren.Die meisten fälschen das Betriebssystem im User-Agent nicht, und beim Fingerprinting geht es eher um quasi eindeutige Kombinationen von Eigenschaften als um das Betriebssystem selbst. Die Entdeckung ist interessant, aber der Artikel wirkt zu sehr von einem LLM geschrieben, was Vertrauen kostet.
So können sie Bot-Erkennung leichter umgehen und Daten, die sie von anderen Websites gesammelt haben, an Kunden verkaufen.
Dass der Text mit einem LLM geschrieben wurde, steht im Artikel und im Blog offen; es wurde nicht verheimlicht und auch nicht so getan, als sei er von einem Menschen. Wegen Zeitmangels hätte ich den Artikel sonst gar nicht veröffentlichen können, und ich bin bereit, die Verantwortung für diese Entscheidung zu übernehmen.
Browser fügen ständig Funktionen hinzu und beheben Bugs, und das meiste davon lässt sich mit JavaScript erkennen.
Eine clevere Strategie: alle Fingerprinting-Techniken per KI analysieren und veröffentlichen und nach der Kontroverse die Browser dazu bringen, sie zu blockieren; dadurch verdient das eigene Scraping-Geschäft mehr Geld.
Ohne solche Firmen wäre Browser-Fingerprinting nicht so verbreitet wie heute, und das Internet wäre besser dran. Da bevorzuge ich eher Texte von klar erkennbaren Gegenparteien mit offensichtlichen Interessen, etwa fingerprint.js.
Ein weiterer Grund, auf korrekt gerundete transzendente Funktionen hinzuarbeiten.
Ich habe kürzlich erfahren, dass dieses Problem praktisch gelöst ist. Siehe die zweite Keynote unter https://arith2026.org/program.html.
libm-Funktionen sind großartig, dürfen aber keine furchtbare Worst-Case-Performance haben wie früherpowin glibc.Man könnte versuchen, den hochpräzisen Fallback-Pfad, der nahe an Rundungsgrenzen verwendet wird, manuell per SLP zu vektorisieren, um die Worst-Case-Performance zu verbessern; für die meisten Zwecke reicht es aber bereits. Es ist überraschend, dass JavaScript-Engines nicht weiterhin das in der ECMAScript-Spezifikation empfohlene
fdlibmverwenden; und wennMath.tanhein Hot Path in JavaScript ist, ist das ziemlich ungewöhnlicher Code.Im Engineering wurde Festkommaarithmetik oft genutzt, weil sie auf viel einfacherer Hardware läuft und sich Fehler mathematisch leicht modellieren lassen. IEEE-754-Gleitkomma ist auch theoretisch fragwürdig; bei Genauigkeitsverlusten können kleine Ganzzahlen unterhalb der Mantisse, also Integers mit weniger als 24 Bit, manchmal besser sein als 32-Bit-Floats.
Ich fände es gut, wenn diese Technik zu https://coveryourtracks.eff.org/ hinzugefügt würde, damit ich sehen kann, wie einzigartig die Ergebnisse meiner mathematischen Funktionen in einer größeren Population sind.
Ob das stimmt, weiß ich nicht, aber ich glaube, coveryourtracks.eff.org verwendet nur etwa 25 Signale.
Man merkt, dass der Artikel von Claude geschrieben wurde.
Wenn man den Claude-Link anklickt, wird folgender Prompt übergeben:
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 und Mullvad Browser haben es am Ende ebenfalls aufgegeben, das Betriebssystem zu verbergen; vielleicht hätten sie das aber nicht tun sollen.
Es scheint einfach viel zu viele Fingerprinting-Pfade zu geben.
Innerhalb und außerhalb des Browsers gibt es so viele betriebssystemspezifische Verhaltensunterschiede, dass sie kaum alle zu behandeln sind. Selbst wenn Canvas-Extraktion blockiert oder verrauscht wird, können Rendering-Unterschiede sichtbar werden; Entwickler des Tor Browsers haben bestätigt, dass sie nicht einmal Unterschiede zwischen X11 und Wayland verbergen können, geschweige denn zwischen völlig verschiedenen Betriebssystemen. https://forum.torproject.org/t/linux-is-it-alright-to-run-th...
navigator.platform, daher ist es sehr leicht, Nicht-Windows-Umgebungen zu erkennen.Mit dem bevorzugten Plugin zum Injizieren von JavaScript kann man einfach folgenden Code einfügen:
let oldTanh = Math.tanh; Math.tanh = x => oldTanh(x) + Math.random()/10000000;Math.tanh = Math.random;.Aktuelle glibc-Versionen verwenden das exakt gerundete
tanhaus CORE-MATH und liefern daher andere Ergebnisse als die im Artikel zitierten Werte.Ob sich korrektes Runden auch für andere transzendente Funktionen mit vernünftiger Performance umsetzen lässt, ist noch unklar; daher hinterlässt jede Funktion ihren eigenen Fingerprint.
Chrome umfasst allein beim ausführbaren Code Hunderte MB; ich hätte erwartet, dass etwa die Hälfte der User-Space-Bibliotheken statisch gelinkt ist.
Außerdem dachte ich,
tanhsei keine Funktionsaufruf, sondern eine eingebaute Operation, die der JavaScript-JIT als CPU-Instruktion ausgibt; es wirkt seltsam, für mathematische Operationen überdlsym()in eine Funktion verzweigen zu müssen. CPU-Instruktionen selbst können allerdings ebenfalls fingerprintbar sein.Mikrocode profitiert nicht von Vorteilen wie Branch Prediction und ist in der Praxis langsamer als eine Software-Implementierung.
Ich frage mich, ob man diesen Kampf gewinnen kann.
Wenn man genügend Funktionen ausführt, kann man wahrscheinlich anhand einer Kombination aus Laufzeitverhältnissen und Rundungsergebnissen nicht nur das Betriebssystem und das genaue Modell schätzen, sondern sogar andere Jobs, die auf derselben Maschine laufen. Es scheint eher möglich, es etwas schwieriger zu machen, als es vollständig zu verhindern.
Am Ende müssen Gesellschaft und Recht aufholen. So wie Türschlösser Einbrüche nicht vollständig verhindern, aber durch gesellschaftliche Ächtung und Strafverfolgung ergänzt werden, sollte diese Art der Verfolgung von Personen illegal gemacht werden, und Unternehmen sowie Beschäftigte, die davon profitieren, sollten gesellschaftlich geächtet werden.
In Ländern wie Russland, Myanmar oder Nordkorea funktioniert der Rechtsstaat nicht, und lokale Behörden schützen Kriminelle, die Ausländer betrügen, teils aktiv; daher trägt die Türschloss-Analogie nicht.