TLS-Fingerprinting identifiziert die Software, die eine HTTPS-Verbindung öffnet, indem es darauf achtet, wie sie sie öffnet – welche Cipher sie anbietet und in welcher Reihenfolge, welche Erweiterungen und elliptischen Kurven sie auflistet – bevor überhaupt ein Anfrageinhalt gesendet wird. Jede TLS-Bibliothek und jede Browserversion sagt einem Server auf leicht unterschiedliche Weise „Hallo“, und diese Begrüßung ist für den Server im Klartext sichtbar, obwohl alles danach verschlüsselt ist. JA3 und sein Nachfolger JA4 verwandeln die Begrüßung in einen kurzen Hash. Anti-Bot-Systeme vergleichen diesen Hash mit dem, was der behauptete Browser hätte erzeugen sollen. Genau deshalb wird ein Python-Skript, das sich als Chrome ausgibt und über eine einwandfreie Residential-IP verbindet, trotzdem erkannt: Die IP sagte „Heimnutzer in Berlin“, der TLS-Handshake sagte „OpenSSL in einem Skript“.
Woher der Fingerprint kommt: das ClientHello
Eine HTTPS-Verbindung beginnt mit einem TLS-Handshake. Die allererste Nachricht, die der Client sendet, ist das ClientHello. Sie ist unverschlüsselt – das muss sie sein, denn die Verschlüsselung ist noch nicht ausgehandelt – und enthält unter anderem:
- die TLS-Version, die der Client unterstützt;
- die Liste der Cipher Suites, die er verwenden möchte, in seiner Präferenzreihenfolge;
- eine Liste von Erweiterungen – SNI (der Hostname), ALPN (welche Anwendungsprotokolle, z. B.
h2,http/1.1), Supported Groups (elliptische Kurven), Signaturalgorithmen, Key Share, Session Ticket usw. – wiederum in einer bestimmten Reihenfolge; - die elliptischen Kurven und Punktformate, die es unterstützt.
Keiner dieser Werte ist geheim und keiner wird pro Website gewählt; sie sind in die TLS-Bibliothek und die Anwendung, die sie verwendet, eingebacken. Chrome 128 sendet ein bestimmtes ClientHello; Firefox sendet ein anderes; das ssl-Modul von Python (OpenSSL) sendet ein drittes; Go's crypto/tls ein viertes; curl ein fünftes. Der Server sieht das ClientHello bei jeder Verbindung ohnehin – er muss es, um darauf zu antworten. Es aufzuzeichnen und zu hashen kostet nichts.
JA3 und JA4: Den Handshake in eine Signatur verwandeln
JA3
2017 von Salesforce-Forschern eingeführt, verkettet JA3 fünf Felder des ClientHello – TLS-Version, Cipher Suites, Erweiterungen, elliptische Kurven, Punktformate elliptischer Kurven – als kommagetrennte Dezimallisten und hasht die Zeichenkette dann mit MD5. Das Ergebnis ist ein 32-stelliger Fingerprint wie cd08e31494f9531f560d64c695473da9. Jeder kann ihn aus einem Paketmitschnitt berechnen, und Listen, die JA3-Hashes bekannten Clients zuordnen („dieser Hash = Chrome 120 unter Windows“, „dieser Hash = python-requests“), sind weit verbreitet.
JA3 hat eine Schwäche, die für Umgehungszwecke zum Feature wurde: Da es die Erweiterungsliste in Reihenfolge hasht und Chrome (seit Version 110) die Reihenfolge der Erweiterungen bei jeder Verbindung randomisiert, erzeugt eine einzige Chrome-Installation viele verschiedene JA3-Hashes. Das wurde absichtlich getan, um Server davon abzuhalten, sich auf einen Fingerprint zu versteifen – und es machte JA3 für die Identifizierung von Browsern viel weniger nützlich.
JA4
JA4, 2023 von FoxIO veröffentlicht, wurde entwickelt, um das zu überleben. Es sortiert die Cipher- und Erweiterungslisten vor dem Hashen (sodass das Mischen von Chrome keine Rolle mehr spielt), lässt einige Felder menschenlesbar und bezieht weitere Signale ein: ob die Verbindung über TCP oder QUIC läuft, den SNI-Typ, den ALPN-Wert, die TLS-Version sowie die Anzahl der Cipher und Erweiterungen. Ein JA4-Fingerprint sieht so aus: t13d1516h2_8daaf6152771_e5627efa2ab1: Der erste Block sagt „TLS 1.3 über TCP, 15 Cipher, 16 Erweiterungen, ALPN h2“, die anderen beiden sind gekürzte Hashes der sortierten Cipher-Liste bzw. der sortierten Erweiterungsliste plus Signaturalgorithmen. JA4 ist eigentlich eine Familie (JA4 für TLS, JA4H für HTTP-Header, JA4S für die Serverseite, JA4X für Zertifikate und andere); wenn Anbieter von Anti-Bot-Lösungen heute „TLS-Fingerprint“ sagen, meinen sie meist JA4 oder ein proprietäres Äquivalent, das auf dieselbe Weise aufgebaut ist.
Warum der Proxy nicht helfen kann
Ein Proxy leitet den TLS-Handshake weiter; er schreibt ihn nicht um. Bei einem HTTP-Proxy sendet der Client CONNECT host:443, der Proxy öffnet einen TCP-Tunnel, und das eigene ClientHello des Clients reist unverändert durch den Tunnel zum Ziel. Bei SOCKS5 passiert dasselbe eine Ebene tiefer. Der Zielserver sieht daher zwei unabhängige Fakten:
- die Quell-IP – die des Proxys, residential und einwandfrei;
- das ClientHello – das des Clients, das genau sagt, welche Bibliothek es erstellt hat.
Die Anti-Bot-Logik stellt dann eine einfache Frage: Stimmt der TLS-Fingerprint mit dem User-Agent überein? Der User-Agent-Header behauptet „Chrome 128 unter Windows“. Der JA4 sagt „OpenSSL 3.x über Python“. Echtes Chrome erzeugt diesen JA4 nie. Die Anfrage wird markiert – nicht weil die IP schlecht ist, sondern weil die Geschichte intern inkonsistent ist. Dies ist der häufigste Grund, warum ein „sauberer“ Residential-Proxy auf geschützten Websites trotzdem CAPTCHAs erhält, und warum wir sagen, dass ein Proxy die Frage woher beantwortet, nicht wer; siehe was ein Proxy verbirgt und was nicht.
Der Proxy kann in einer Hinsicht eine Rolle spielen: Einige Anbieter beenden TLS selbst (ein „Man-in-the-Middle“-Proxy, der entschlüsselt und wieder verschlüsselt, wobei Sie sein Zertifikat installieren müssen). In diesem Fall sieht das Ziel das ClientHello des Proxys, nicht Ihres – was normalerweise schlechter ist, da es sich um eine serverseitige Bibliothek handelt, nicht um einen Browser. Gewöhnliche Proxys tun das nicht.
Wie jeder Client-Typ aussieht
| Client | Was sein TLS-Fingerprint sagt | Konsistent mit einem Browser-User-Agent? |
|---|---|---|
| Echtes Chrome / Firefox / Safari | Dieser Browser und diese Version auf diesem Betriebssystem | Ja – es ist der Browser |
Python requests, httpx, aiohttp | OpenSSL, wie vom ssl-Modul von Python konfiguriert | Nein – unabhängig von den Headern als Skript erkennbar |
Node.js fetch / axios | Node's OpenSSL/BoringSSL-Build | Nein |
Go net/http | Go's eigener TLS-Stack; unverwechselbar | Nein |
| curl (Standard-Build) | OpenSSL/LibreSSL wie gebaut | Nein |
| Headless Chrome über Puppeteer/Playwright | Echtes Chrome – korrektes TLS | Ja für TLS; andere Signale (Automatisierungsflags, fehlende Plugins) können trotzdem leaken |
| „Impersonating“-Clients (curl-impersonate, curl_cffi, tls-client) | Das ClientHello eines gewählten Browsers, bytegenau reproduziert | Ja, wenn Sie auch die Header an denselben Browser anpassen |
So erhalten Sie einen konsistenten Fingerprint
Es gibt drei ehrliche Wege, in aufsteigender Kostenreihenfolge.
- Verwenden Sie einen echten Browser. Automatisieren Sie Chrome oder Firefox mit Playwright oder Puppeteer; das TLS ist dann wirklich das des Browsers. Langsamer und schwergewichtiger als rohes HTTP, aber für geschützte Websites ist es die Grundlinie. Kombinieren Sie jeden Browserkontext mit einem eigenen Proxy – siehe Proxys in Playwright, Puppeteer und Selenium.
- Verwenden Sie einen impersonierenden HTTP-Client. Bibliotheken wie curl_cffi (Python, basierend auf curl-impersonate) und tls-client reproduzieren das ClientHello und die HTTP/2-Einstellungen bestimmter Browser, sodass Sie Scraper-Geschwindigkeit mit einem Browser-Fingerprint erhalten. Sie müssen dann alle anderen Header konsistent mit derselben Browserversion halten – User-Agent,
Accept-Language,sec-ch-uaClient Hints – sonst tauschen Sie einen Widerspruch gegen einen anderen. Unser Python-Proxy-Leitfaden zeigt den Wechsel vonrequestszucurl_cffi. - Hören Sie auf, so zu tun. Wenn ein Ziel eine offizielle API anbietet, verwenden Sie sie mit Ihrer echten Client-Identität. TLS-Fingerprinting ist nur dann ein Problem, wenn der Fingerprint der Behauptung widerspricht.
Was nicht funktioniert: einen Chrome-User-Agent auf requests zu setzen. Das ändert einen Header und lässt den Handshake unberührt – die Diskrepanz ist jetzt sogar schärfer, denn ein einfacher python-requests-UA mit einem OpenSSL-Fingerprint ist zumindest in sich konsistent.
Das große Ganze: Fingerprints stapeln sich
TLS ist eine Ebene. Moderne Anti-Bot-Anbieter fingerprinten auch die HTTP/2-Verbindung (SETTINGS-Frame-Werte, Fenstergrößen, Header-Reihenfolge und Pseudo-Header-Reihenfolge – manchmal auch Akamai-Fingerprinting genannt), den TCP/IP-Stack (Fenstergröße, TTL, Optionen; klassisches p0f) und natürlich den Browser selbst über JavaScript, das ein HTTP-Client überhaupt nicht ausführen kann. Jede Ebene muss dieselbe Geschichte erzählen wie die anderen und wie die IP. Eine Residential-IP mit Browser-TLS-Fingerprint und Browser-HTTP/2-Einstellungen, aber ohne JavaScript-Ausführung ist auf einer Website, die erwartet, dass die JS-Herausforderung läuft, immer noch eine Anomalie. Deshalb ist die ehrliche Antwort auf „Welcher Proxy vermeidet Erkennung?“ „Keiner für sich allein“ – und warum unsere Rankings gewichten, was der Anbieter über die IP hinaus tut; siehe den Elite-Proxy-Vergleich.
So sehen Sie Ihren eigenen Fingerprint
Mehrere öffentliche Seiten geben den JA3/JA4 zurück, den sie für Ihre Verbindung berechnen, zusammen mit der Angabe, welcher Browser es Ihrer Meinung nach ist. Laden Sie eine von einem echten Browser, holen Sie sie dann mit Ihrem Skript über denselben Proxy und vergleichen Sie. Wenn die beiden unterschiedlich sind, haben Sie den Grund gefunden, warum Ihr Skript anders behandelt wird als Ihr Browser – und keine Proxy-Änderung wird das beheben. Fügen Sie dies zu den Checks in So testen Sie einen Proxy hinzu, wenn das Ziel bekanntermaßen Enterprise-Anti-Bot einsetzt.
Häufig gestellte Fragen
Was ist JA3?
Ein MD5-Hash von fünf Feldern des TLS-ClientHello (Version, Cipher, Erweiterungen, Kurven, Punktformate), der zur Identifizierung der Client-Software verwendet wird. Er funktioniert gut für Skripte und Bibliotheken; für Chrome wurde er unzuverlässig, als Chrome begann, die Erweiterungsreihenfolge zu randomisieren.
Was ist JA4?
Der Nachfolger von JA3: Er sortiert die Listen vor dem Hashen, sodass das Mischen der Erweiterungen ihn nicht verändert, behält einen Teil des Fingerprints lesbar und bezieht Transport (TCP/QUIC), ALPN und Zählungen ein. Er ist die Grundlage der meisten aktuellen TLS-Fingerprint-Erkennung.
Ändert ein Residential-Proxy meinen TLS-Fingerprint?
Nein. Der Proxy tunnelt Ihren Handshake unverändert; das Ziel sieht die IP des Proxys und Ihr ClientHello. Nur die Client-Software bestimmt den Fingerprint.
Kann ich in Python den TLS-Fingerprint eines Browsers fälschen?
Ja, mit impersonierenden Clients wie curl_cffi, die das ClientHello und das HTTP/2-Verhalten eines gewählten Browsers reproduzieren. Sie müssen die Header konsistent mit demselben Browser halten. Einfache requests/httpx können das nicht.
Ist TLS-Fingerprinting dasselbe wie Browser-Fingerprinting?
Nein. TLS-Fingerprinting liest den Handshake der verschlüsselten Verbindung und identifiziert die Client-Software; Browser-Fingerprinting führt JavaScript aus und identifiziert das Gerät (Canvas, Schriftarten, GPU). Anti-Bot-Systeme verwenden beides plus IP-Reputation und prüfen, ob sie übereinstimmen.
Warum wird dasselbe Skript auf einer Website blockiert und auf einer anderen nicht?
Weil TLS-Fingerprint-Checks ein Feature von Enterprise-Anti-Bot-Produkten sind, nicht des Webs im Allgemeinen. Websites ohne solchen Schutz betrachten den Handshake nie; Websites mit Schutz vergleichen ihn bei jeder Anfrage mit dem User-Agent.