Ein JA4-Fingerprint ist ein dreiteiliger String, a_b_c, der aus einem TLS-ClientHello berechnet wird. Teil a sind lesbare Metadaten (Protokoll, TLS-Version, SNI, Anzahl der Cipher Suites und Extensions, ALPN), Teil b ist ein 12-stelliger SHA-256 der sortierten Cipher-Liste, und Teil c ist ein 12-stelliger SHA-256 der sortierten Extensions plus Signaturalgorithmen. Falls Sie nach b0da82dd1658 gesucht haben: Das ist ein c-Abschnitt, und er gehört zu Chromium. Genauer gesagt erzeugt ihn ein Chromium-basierter Client, wenn er eine TLS-1.3-Session wiederaufnimmt und dabei noch den älteren Codepoint der ALPS-Extension verwendet. Der Rest dieser Seite zeigt, woher wir das wissen und wie Sie jeden JA4-String selbst entschlüsseln.
So ist ein JA4-Fingerprint aufgebaut: das Format a_b_c
Die offizielle technische Spezifikation von JA4 von FoxIO definiert den Fingerprint als ein menschenlesbares Präfix und zwei gekürzte Hashes, verbunden durch Unterstriche. GREASE-Werte werden überall ignoriert, und alle Hashes sind kleingeschrieben.
| Abschnitt | Zeichen | Was er kodiert | Mögliche Werte |
|---|---|---|---|
| a | 1 | Transport | t = TLS über TCP, q = QUIC, d = DTLS |
| a | 2 | Höchste TLS-Version (aus supported_versions, falls vorhanden, sonst die ClientHello-Version) | 13, 12, 11, 10, s3, d2, 00 = unbekannt… |
| a | 1 | SNI vorhanden? | d = Domain (SNI gesendet), i = kein SNI (meist Verbindung zu einer reinen IP) |
| a | 2 | Anzahl der Cipher Suites (ohne GREASE) | 00–99 |
| a | 2 | Anzahl der Extensions (ohne GREASE, mit SNI und ALPN) | 00–99 |
| a | 2 | Erstes und letztes Zeichen des ersten ALPN-Werts | h2, h1 (http/1.1), h3, 00 = kein ALPN |
| b | 12 | SHA-256 der Cipher Suites als 4-stelliges Hex, sortiert, kommagetrennt | 000000000000, falls keine |
| c | 12 | SHA-256 der Extensions (sortiert, SNI 0000 und ALPN 0010 entfernt) + _ + Signaturalgorithmen in Übertragungsreihenfolge | 000000000000, falls keine |
Zwei Details sorgen oft für Verwirrung. Erstens enthält die Extension-Anzahl in Teil a SNI und ALPN, der Extension-Hash in Teil c aber nicht. Derselbe Client erzeugt also dasselbe c, egal ob er sich mit einem Hostnamen oder einer IP verbindet. Zweitens werden Signaturalgorithmen in der Reihenfolge gehasht, in der der Client sie gesendet hat, nicht sortiert. Ein Client, der seine Signaturpräferenzen umstellt, ändert also c, selbst bei identischen Extensions.
t13d1516h2_8daaf6152771_… Stück für Stück entschlüsselt
t: TLS über TCP, nicht QUIC.13: Der Client bietet TLS 1.3 als höchste Version an.d: Eine SNI-Extension war vorhanden, der Client verband sich also mit einem Domainnamen.15: 15 Cipher Suites nach Entfernen von GREASE.16: 16 Extensions nach Entfernen von GREASE, SNI und ALPN mitgezählt.h2: Der erste ALPN-Wert isth2, der Client bevorzugt also HTTP/2.8daaf6152771: der Hash dieses sortierten Cipher-Strings, den Sie mit jedem SHA-256-Tool nachrechnen können:
printf '%s' "002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9" \
| sha256sum | cut -c1-12
# 8daaf6152771
Diese Liste besteht aus den drei TLS-1.3-Suites plus den zwölf älteren TLS-1.2-Suites von Chrome. Jeder Chromium-Build, den wir geprüft haben, von den FoxIO-Beispielen bis zu einem Headless-Chrome 148, erzeugt immer noch 8daaf6152771. Der b-Abschnitt sagt Ihnen also „TLS-Stack aus der Chromium-Familie“ und fast nichts über die Version. Versionsunterschiede zeigen sich in c.
Ein kleiner Vorbehalt, falls Sie die Spezifikation genau lesen: Ihre Zusammenfassung des Algorithmus zeigt t13d1516h2_8daaf6152771_b186095e22b6, während ihr durchgerechnetes Beispiel e5627efa2ab1 ergibt. Wir haben das Beispiel nachgerechnet und e5627efa2ab1 erhalten. Betrachten Sie den ersten String also als illustrativ.
Was b0da82dd1658 bedeutet
b0da82dd1658 ist der c-Abschnitt eines Chromium-JA4. Es ist der Hash genau dieses Strings:
0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601
Sie können es selbst prüfen:
printf '%s' "0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601" \
| sha256sum | cut -c1-12
# b0da82dd1658
Drei Extensions in dieser Liste identifizieren den Client:
0029(pre_shared_key). Das ist die Wiederaufnahme einer TLS-1.3-Session. Sie erscheint nur, wenn der Client bereits ein Ticket aus einer früheren Verbindung zum selben Server hat. RFC 8446 §4.2.11 definiert sie. Ohne sie ergibt derselbe Browser den Hash02713d6af862.4469(ALPS, ursprünglicher Codepoint). Application-Layer Protocol Settings ist eine Chrome-Extension. BoringSSL hat dafür im September 2023 einen neuen Codepoint eingeführt (0x44cd), und aktuelles Chrome sendet den neuen.4469deutet also auf einen älteren Chromium-Build oder ein Tool, das einen solchen kopiert.fe0d(Encrypted Client Hello). Chrome sendet bei gewöhnlichen Verbindungen eine GREASE-ECH-Extension.
FoxIOs eigene ja4plus-mapping.csv ordnet t13d1517h2_8daaf6152771_b0da82dd1658 und t13i1516h2_8daaf6152771_b0da82dd1658 als „Chromium Browser“ ein. Die Rechnung im Präfix geht auf: 15 gehashte Extensions plus SNI plus ALPN ergeben 17 mit SNI (d) und 16 ohne (i). Das entlarvt auch eine Inkonsistenz, die online oft wiederholt wird. Ein String wie t13d1516h2_8daaf6152771_b0da82dd1658 kann nicht aus einem einzigen echten ClientHello stammen: Mit SNI und ALPN müssten diese 15 gehashten Extensions eine Anzahl von 17 ergeben.
Wir haben den Wert auch direkt reproduziert. Am 2026-10-03 schickte curl_cffi 0.16.3 mit impersonate="chrome131" seine erste Anfrage an tls.peet.ws als t13d1516h2_8daaf6152771_02713d6af862. Die zweite Anfrage in derselben Session, die die TLS-Session wiederaufnahm, kam als t13d1517h2_8daaf6152771_b0da82dd1658 zurück. Kurz gesagt bedeutet b0da82dd1658 „ein ClientHello im Chromium-Stil, älterer ALPS-Codepoint, wiederaufgenommene Session“. Das umfasst echte ältere Builds von Chrome, Edge, Brave und Opera, eingebettetes Chromium und Impersonation-Bibliotheken, die auf ein Chrome-Profil vor der Umstellung festgelegt sind. Ein JA4 allein kann diese nicht unterscheiden.
Referenztabelle: echte JA4-Werte nach Client
Die folgenden Werte stammen aus nur zwei Quellen: den veröffentlichten Beispielen und der Mapping-Datei von FoxIO sowie unseren eigenen Mitschnitten gegen tls.peet.ws am 2026-10-03 (Versionen angegeben). Bibliothekswerte hängen stark vom TLS-Backend und seinen Build-Optionen ab, behandeln Sie die Bibliothekszeilen also als Beispiele, nicht als universelle Konstanten. Zeilen, die wir nicht verifizieren konnten, haben wir weggelassen, darunter einen eigenen Mitschnitt von echtem Firefox und Safari.
| Client | JA4 | Quelle |
|---|---|---|
| Headless Chrome 148 (Linux), neue Verbindung | t13d1516h2_8daaf6152771_d8a2da3f94cd | Unser Mitschnitt, Playwright Chromium |
| Derselbe Browser, wiederaufgenommene Session | t13d1517h2_8daaf6152771_b6f405a00624 | Unser Mitschnitt |
| Chromium, älterer ALPS-Codepoint, neu / wiederaufgenommen | t13d1516h2_8daaf6152771_02713d6af862 / t13d1517h2_8daaf6152771_b0da82dd1658 | FoxIO-Mapping-CSV; reproduziert mit curl_cffi chrome131 |
| Chrome über QUIC | q13d0312h3_55b375c5d22e_178839b6cec1 | FoxIO-README |
| Mozilla Firefox (Version nicht angegeben) | t13d1715h2_5b57614c22b0_7121afd63204 | FoxIO-Mapping-CSV |
| Safari (Version nicht angegeben) | t13d2014h2_a09f3c656075_14788d8d241b | FoxIO-Mapping-CSV |
| curl 8.5.0 / OpenSSL 3.0.13 (Ubuntu) | t13d3112h2_e8f1e7e78f70_b26ce05bbdd6 | Unser Mitschnitt; identisch auf tls.peet.ws, BrowserLeaks und Scrapfly |
| Python requests 2.31 / urllib3 2.0.7, OpenSSL 3.0.13 | t13d3112h1_e8f1e7e78f70_b26ce05bbdd6 | Unser Mitschnitt |
| Go 1.24.1 net/http (Standard-Client) | t13d1311h2_f57a46bbacb6_e7c285222651 | Unser Mitschnitt |
curl_cffi 0.16.3, impersonate="chrome146" | t13d1516h2_8daaf6152771_d8a2da3f94cd | Unser Mitschnitt |
curl_cffi 0.16.3, impersonate="firefox147" | t13d1717h2_5b57614c22b0_3cbfd9057e0d | Unser Mitschnitt |
curl_cffi 0.16.3, impersonate="safari2601" | t13d2013h2_a09f3c656075_7f0f34a4126d | Unser Mitschnitt |
Die Muster sind wichtiger als die einzelnen Zeilen:
- Der c-Abschnitt identifiziert oft die TLS-Bibliothek, nicht die Anwendung. curl und Python auf demselben OpenSSL-3-Build teilen sich
b26ce05bbdd6. Die Mapping-Datei von FoxIO enthält einen Python-Eintrag mit anderem Präfix, aber demselben c. Go-Clients in der FoxIO-Datei teilen siche7c285222651mit unserem Go-1.24-Mitschnitt. - requests zeigt
h1. urllib3 2.x bietet in ALPN nurhttp/1.1an, der a-Abschnitt verrät dem Server also schon vor dem ersten Header, dass er nicht mit einem Browser spricht. - Eine reine Bibliothek fällt schon an ihren Zählwerten auf. 31 Cipher Suites (OpenSSL-Standard) oder 13 Cipher Suites mit 11 Extensions (Go) sehen ganz anders aus als das 15/16-Muster, das jeder aktuelle Chromium-Build sendet.
- Die Wiederaufnahme ändert c bei jedem Browser. Firefox geht in unseren curl_cffi-Mitschnitten bei wiederaufgenommenen Sessions von 17 auf 18 Extensions, Safari von 13 auf 14. Eine Erkennungsregel, die nur den Wert für neue Verbindungen auf die Allowlist setzt, schlägt bei echten wiederkehrenden Besuchern fehl.
Rechnen Sie damit, dass sich die Chrome-Zeile weiter bewegt. Das neueste Profil chrome150 von curl_cffi fügt drei Signaturalgorithmen hinzu: 0904, 0905 und 0906. Das sind die ML-DSA-Codepoints aus dem IETF-Entwurf, und sie machen aus c den Wert 806a8c22fdea. Gegen einen stabilen Chrome-150-Build konnten wir das nicht bestätigen, betrachten Sie es also als Vorschau, nicht als Referenzwert.
Warum JA4 Cipher Suites und Extensions sortiert
JA4 sortiert Cipher Suites und Extensions, weil Chrome die Reihenfolge seiner Extensions absichtlich zufällig wählt und ein reihenfolgeabhängiger Fingerprint (JA3) dadurch nicht mehr stabil war. Chrome führte die Permutation der TLS-ClientHello-Extensions um Chrome 110 Anfang 2023 ein. Ziel war, dass Server und Middleboxes sich nicht länger auf ein festes Layout verlassen. Fastly hat den Effekt gemessen: Da JA3 Extensions in Übertragungsreihenfolge hasht, erzeugt eine einzige Chrome-Installation praktisch bei jeder Verbindung einen anderen JA3.
JA4 löst das, indem es vor dem Hashen sortiert. FoxIO hat es im September 2023 als Teil der JA4+-Suite veröffentlicht (Wiederveröffentlichung bei APNIC). Inzwischen stellen es Cloudflare Bot Management, AWS CloudFront und WAF, Google Cloud Armor, Fastly, Akamai und weitere bereit, die im FoxIO-README aufgeführt sind.
Für Scraper hat das zwei Seiten. Die Reihenfolge der eigenen Extensions zu randomisieren, ändert den Fingerprint nicht mehr, dieser Trick ist also tot. Was weiterhin zählt, ist die Menge der Cipher Suites, die Menge der Extensions und die Reihenfolge der Signaturalgorithmen. In der Praxis heißt das: den TLS-Stack nutzen, den ein echter Browser nutzt, oder eine Bibliothek, die einen solchen genau nachbildet. Wenn Sie die Sicht in Originalreihenfolge brauchen (etwa für einen Vergleich mit JA3), definiert die Spezifikation JA4_o und die Rohvarianten JA4_r / JA4_ro. BrowserLeaks liefert alle vier. Unser Erklärartikel zu TLS-Fingerprinting behandelt JA3 ausführlicher.
Die JA4+-Familie: JA4S, JA4H, JA4X, JA4T
JA4 ist eine Methode in einer größeren Suite. Die anderen betrachten den Server, die HTTP-Schicht, Zertifikate und TCP, und sie stehen unter einer anderen Lizenz.
| Methode | Fingerprint von | Format, kurz |
|---|---|---|
| JA4S | ServerHello des Servers | Protokoll + Version + Anzahl der Extensions + ALPN, dann die gewählte Cipher Suite, dann ein Hash der Server-Extensions |
| JA4H | HTTP-Anfrage | Methode (ge, po…), Version (11, 20), Cookie c/n, Referer r/n, Anzahl der Header, erste 4 Zeichen von Accept-Language; dann Hashes der Header-Namen in Reihenfolge, der sortierten Cookie-Namen und der sortierten Paare Cookie-Name=Wert |
| JA4X | X.509-Zertifikat | Hashes der Issuer-RDN-OIDs, Subject-RDN-OIDs und Extension-OIDs (wie das Zertifikat gebaut wurde, nicht seine Werte) |
| JA4T | TCP-SYN | Fenstergröße, TCP-Optionen in Reihenfolge, MSS, Window Scale, z. B. 64240_2-1-3-1-1-4_1460_8 für Windows 11 |
Die Formate stammen aus FoxIOs Diagrammen zu den technischen Details und der Python-Referenzimplementierung. Für Scraping ist JA4H am wichtigsten. Sein b-Abschnitt hasht Header-Namen in der gesendeten Reihenfolge, ein Client, der die Header von Chrome in falscher Reihenfolge sendet, fällt also auf, selbst wenn jeder Wert stimmt. Unser Artikel zu HTTP/2-Fingerprinting behandelt die verwandten Signale aus SETTINGS und Pseudo-Header-Reihenfolge. JA4T verrät das Betriebssystem: Das SYN eines Linux-Servers sieht nicht aus wie Windows, egal was der User-Agent sagt.
Lizenzierung
Laut dem Lizenzabschnitt des Repositorys steht JA4 (der TLS-Client-Fingerprint) wie JA3 unter BSD 3-Clause, und FoxIO erklärt, darauf keine Patentansprüche zu erheben. JA4S, JA4L, JA4LS, JA4H, JA4X, JA4SSH, JA4T, JA4TS, JA4TScan, JA4D, JA4D6 und die übrigen „JA4+“-Methoden sind zum Patent angemeldet und stehen unter der FoxIO License 1.1. Diese Lizenz erlaubt interne und akademische Nutzung, ein Anbieter, der JA4+-Fingerprinting als Teil eines Produkts verkauft, braucht aber eine OEM-Lizenz.
QUIC und HTTP/3: was das Präfix q verrät
Ein JA4, der mit q beginnt, wurde aus einem QUIC-Initial-Paket berechnet, der Client baute also HTTP/3 auf. QUIC transportiert ein TLS-1.3-ClientHello in seinen CRYPTO-Frames. Die Schutzschlüssel des Initial-Pakets werden aus der Destination Connection ID abgeleitet, die der Client wählt (RFC 9001 §5.2). Jeder Beobachter auf dem Pfad und jeder Edge-Server kann es also entschlüsseln und das ClientHello genauso fingerprinten wie über TCP.
Chromes QUIC-Fingerprint sieht ganz anders aus als sein TCP-Fingerprint: q13d0312h3_55b375c5d22e_178839b6cec1 im Beispiel von FoxIO. Das sind 3 Cipher Suites (nur TLS 1.3, weil QUIC ältere Versionen verbietet) und ALPN h3. Für die Automatisierung ist das relevant, weil Browser auf HTTP/3 wechseln, sobald eine Website es anbietet, während die meisten HTTP-Clients das nie tun. Die dokumentierten JA4 Signals von Cloudflare enthalten einen Wert h2h3_ratio_1h: den Anteil des Traffics eines bestimmten JA4, der über HTTP/2 statt HTTP/3 ankommt. Ein „Chrome“-TLS-Fingerprint, der auf einer HTTP/3-Website nie über QUIC auftaucht, ist ein statistischer Ausreißer. Laut README von curl_cffi wird die Imitation von HTTP/3-Fingerprints seit v0.15.0 unterstützt.
So sehen Sie Ihren eigenen JA4
Am schnellsten geht es mit einem Echo-Dienst, der Ihr ClientHello liest und den Fingerprint zurückgibt. Diese drei lieferten in unseren Tests JA4, und sie stimmten Byte für Byte überein:
- tls.peet.ws/api/all: JSON mit
tls.ja4,tls.ja4_r, JA3, dem HTTP/2-Akamai-Fingerprint undhttp_version. - tls.browserleaks.com/json: JSON mit
ja4,ja4_r,ja4_o,ja4_ro. - Das JA3/JA4-Tool von Scrapfly, dessen API unter
tools.scrapfly.io/api/fp/ja3ja4undja4_rliefert.
curl -s https://tls.peet.ws/api/all | python3 -c \
"import sys, json; d = json.load(sys.stdin); print(d['http_version'], d['tls']['ja4'])"
Führen Sie dieselbe Prüfung über Ihren Proxy aus, nicht nur vom eigenen Laptop. Ein Forward-Proxy, der per CONNECT tunnelt, reicht Ihr ClientHello unverändert durch, ein TLS-abfangender Proxy, eine Unternehmens-Middlebox oder manche SDK-Schichten setzen dagegen ihr eigenes ein. Zum Beispiel mit einem ProxyHat-Residential-Exit:
curl -s -x http://USERNAME:PASSWORD@gate.proxyhat.com:8080 https://tls.peet.ws/api/all
Wireshark und tshark
Wireshark berechnet JA4 seit Version 4.2.0 nativ, im Display-Filter-Feld tls.handshake.ja4 (und tls.handshake.ja4_r), laut der Referenz der TLS-Felder. FoxIOs JA4+-Plugin (Wireshark 4.4.0 oder neuer) ergänzt den Rest der Suite unter ja4.*, etwa ja4.ja4s, ja4.ja4h und ja4.ja4t. So ziehen Sie Fingerprints aus einem Mitschnitt:
tshark -r capture.pcapng -Y "tls.handshake.ja4" -T fields \
-e ip.dst -e tls.handshake.extensions_server_name -e tls.handshake.ja4
Schneiden Sie auf einer Maschine mit, auf der Sie den Client kontrollieren. Um HTTPS-Traffic eines Headless-Browsers zu fingerprinten, führen Sie ihn lokal aus und schneiden auf dem Loopback- oder ausgehenden Interface mit. Das ClientHello ist unverschlüsselt, für JA4 brauchen Sie also keine TLS-Schlüssel. Für JA4H über HTTPS brauchen Sie sie.
Was das in der Praxis heißt: Header müssen zum Handshake passen
Den User-Agent zu ändern, ändert Ihren JA4 nicht. Ein Python-Skript, das einen Chrome-User-Agent sendet, präsentiert im Handshake trotzdem t13d3112h1_e8f1e7e78f70_b26ce05bbdd6, bevor ein einziger Header gelesen wird. Diese Diskrepanz (behauptet Chrome, verhandelt wie OpenSSL, fragt nach HTTP/1.1) ist eine der billigsten Prüfungen, die ein Edge durchführen kann. Genau dafür sind JA4-Datenbanken gebaut.
Es gibt zwei verbreitete Lösungen. Beide haben Grenzen.
- curl_cffi (Python-Bindings für curl-impersonate) baut ClientHello und HTTP/2-Frames passend zu einem benannten Browserprofil:
requests.get(url, impersonate="chrome"). In unseren Mitschnitten erzeugten seine aktuellen Chrome-Profile denselben JA4 wie ein echtes Headless-Chrome 148. Unser Leitfaden zu curl_cffi behandelt Sessions und Proxies. - uTLS für Go ersetzt das ClientHello von
crypto/tlsdurch einen „Parrot“ wietls.HelloChrome_Autoübertls.UClient(conn, &config, helloID). Sein README sagt ausdrücklich, dass das Nachahmen unvollkommen sein kann und nicht über das ClientHello hinausreicht. Unsere Go-uTLS-Anleitung zeigt, wie Sie es innet/httpeinbinden.
Was Impersonation nicht löst
Ein passender JA4 bringt Sie nur am ersten Filter vorbei.
- Der JA4 muss zur behaupteten Browser-Version passen: Ein Chrome-148-User-Agent mit einem ALPS-Codepoint von vor der Umstellung (
b0da82dd1658) ist eine eigene kleine Diskrepanz. - Auch die Header-Reihenfolge für JA4H muss stimmen.
- JA4T und IP-Daten verraten Host-Betriebssystem und Netzwerk.
- JavaScript-Challenges laufen in einem HTTP-Client nie.
- Verhalten (Anfragerate, Navigationsmuster) wird separat bewertet.
Wählen Sie das Profil, das zum gesendeten User-Agent passt, halten Sie Sessions offen, damit die Wiederaufnahme normal aussieht, und sorgen Sie für eine Exit-IP, die zum Traffic passt. Ein Residential-Exit behebt die Ebene der Netzwerkreputation, nicht die TLS-Ebene. Prüfen Sie den Fingerprint über den Proxy, wie oben gezeigt.
Zum Schluss: Fingerprints zu verstehen dient dazu, legitime Automatisierung ehrlich und berechenbar zu machen, nicht dazu, an einer Website vorbeizukommen, die automatisierten Zugriff bewusst ablehnt. Respektieren Sie robots.txt und Nutzungsbedingungen, wo sie gelten, und denken Sie daran, dass das Scrapen personenbezogener Daten rechtliche Pflichten mit sich bringt, an denen auch ein perfekter JA4 nichts ändert.






