TLS Fingerprinting (JA3/JA4): Waarom Schone IP's Nog Steeds Geblokkeerd Worden

Je residentiële IP is schoon, je headers zijn perfect, en toch krijg je een 403 bij het eerste verzoek. De oorzaak is je TLS-handshake — de vingerafdruk die anti-botsystemen lezen voordat er enige HTTP wordt uitgewisseld.

Hier is een puzzel waar elke scraper uiteindelijk tegenaan loopt: de residentiële IP is schoon, de User-Agent is een actuele Chrome-string, de headers zijn perfect in orde — en het allereerste verzoek komt terug als 403. Niets wat je roteert lost het op. De reden is dat de blokkade plaatsvond voordat je headers ooit werden gelezen. Moderne anti-botsystemen vingerafdrukken je TLS-handshake, en een standaard Python-, Go- of curl-client maakt zichzelf bekend als een bot in de ClientHello, een laag onder HTTP. Dit is wat JA3 en JA4 fingerprinting doen, en waarom curl een 403 krijgt waar de browser een 200 krijgt op dezelfde URL.

Wat TLS fingerprinting leest

Elke HTTPS-verbinding begint met een TLS-handshake. De client stuurt een ClientHello die, in een specifieke volgorde, adverteert welke TLS-versie het wil, welke cipher suites het ondersteunt, welke extensies het aanbiedt (SNI, ALPN, en meer), welke elliptische krommen, en welke puntformaten. Geen van die dingen noemt je browser direct — maar de exacte combinatie en volgorde is een bijna unieke handtekening van de softwarestack. De lijst van Chrome verschilt van die van Firefox, en beide verschillen sterk van Python's requests of Go's net/http. Lees de handshake, en je kunt de client raden voordat er een byte HTTP is uitgewisseld.

JA3: vijf velden in één MD5-hash

JA3, gepubliceerd in 2017 door ingenieurs bij Salesforce, is de klassieke methode. Het neemt vijf velden uit de ClientHello — TLS-versie, ciphers, extensies, elliptische krommen, en puntformaten — concateneert ze, en haalt de string door MD5. Een concreet voorbeeld: de velden

771,4865-4866-4867,0-11-10-35-16-5-13,29-23-24,0

hashen naar e7d705a3286e19ea42f587b344ee6865 — een vingerafdruk die hoort bij een standaard curl-build. Anti-bot leveranciers houden databases bij van deze hashes. Een verzoek waarvan de JA3 overeenkomt met een bekende scraping-bibliotheek krijgt een strengere snelheidslimiet, een uitdaging, of een directe blokkade. De krachtigste controle is correlatie: als je User-Agent Chrome 120 beweert maar je JA3 zegt python-requests, is die tegenstrijdigheid alleen al genoeg om je te laten falen.

Waarom JA3 plaatsmaakte voor JA4

JA3 heeft een zwakte die het als stabiel signaal brak. Vanaf Chrome 110 en Firefox 114 randomiseren browsers de volgorde van TLS-extensies bij elke verbinding om fingerprinting te weerstaan. Dat betekent dat een echte browser nu een andere JA3-hash produceert bij elke sessie — dus rauwe JA3 geeft valse positieven op echte gebruikers. De reactie van de industrie is JA3N (een genormaliseerde variant die extensies sorteert voor het hashen, waardoor de randomisatie wordt geannuleerd) en JA4, een nieuwere methode van FoxIO gebouwd door de eigen maker van JA3.

JA4 is leesbaarder en moeilijker te vervalsen. Het gebruikt een drie-delige a_b_c indeling, bijvoorbeeld t13d1516h2_8daaf6152771_e5627efa2ab1. Alleen al het voorvoegsel vertelt veel: t voor TCP, 13 voor TLS 1.3, d voor een domeingebaseerde SNI, 15 cipher suites, 16 extensies, en h2 voor HTTP/2 als de eerste ALPN — gevolgd door twee afgekorte hashes van de gesorteerde ciphers en van de extensies plus handtekeningalgoritmen. JA4 is een van een familie: JA4S vingerafdrukt de server, JA4H de HTTP-headers, JA4X het certificaat, en JA4T de ruwe TCP-laag.

Diagram dat een standaardclient toont die wordt geblokkeerd bij de TLS-handshake versus een browservormige client die passeert, voordat er enige HTTP wordt verzonden
De JA3/JA4-opzoeking gebeurt bij de handshake — een niet-overeenkomende vingerafdruk is een 403 voordat je headers ooit worden gelezen.

Waarom een schone IP je niet redt

Dit is het deel dat mensen in de war brengt die alleen in proxies investeren. Een onberispelijke residentiële IP vertelt de site dat het verkeer van een echt netwerk komt. Een browser-niet-overeenkomende TLS-handshake vertelt dat het verkeer van een script komt. Wanneer die twee signalen het oneens zijn, wint de handshake, omdat het veel moeilijker is om per ongeluk te vervalsen. Je kunt door duizend schone exits roteren en nog steeds elk verzoek falen als alle duizend dezelfde python-requests JA3 dragen. De IP en de vingerafdruk zijn afzonderlijke assen — je moet beide goed krijgen.

Concreet toont dat zich in slaagpercentages tegen een Cloudflare-beschermd doelwit: een standaard requests client haalt ongeveer twee procent van de verzoeken, httpx met HTTP/2 doet het iets beter, en een browser-overeenkomende client komt in de midden tachtig. Dezelfde IP-pool in elk geval. De variabele is de TLS-stack. Akamai legt de lat nog hoger door de TLS-vingerafdruk te combineren met een HTTP/2-vingerafdruk — de SETTINGS-framewaarden, venstergroottes en stroomprioriteiten — zodat zelfs een correcte JA3 kan worden gepakt als de HTTP/2-laag gescript lijkt. Onze analyse van waarom Akamai het meeste proxyverkeer blokkeert gaat dieper in op die stack.

Staafdiagram van Cloudflare-slaagpercentages per client, van standaard python-requests via httpx en curl_cffi naar headless browsers
Dezelfde schone IP in elk geval — alleen de TLS-stack verandert het slaagpercentage. De oplossing is de handshake, niet de exit.

De nabootsingsopties die daadwerkelijk slagen

Je kunt geen browser-handshake op een standaardclient schroeven door cipher-strings aan te passen — de OpenSSL en urllib3 knoppen stellen simpelweg niet elke parameter bloot die JA3 leest. Wat werkt is een client die de exacte TLS-dialect van de browser spreekt:

# curl_cffi: a browser-shaped handshake in two lines
from curl_cffi import requests

session = requests.Session(impersonate="chrome120")
r = session.get(
    "https://example.com",
    proxies={"https": "http://USER:PASS@gate.quantumproxies.io:8000"},
    timeout=20,
)
print(r.status_code)  # matched JA3 + a clean residential exit

Merk de proxy op in dat fragment. Nabootsing en een schone exit zijn complementair, geen alternatieven: de browservormige handshake laat je de TLS-controle passeren, en een schone residentiële IP houdt het verzoek van reputatieblokkades. Combineer ze en je lost beide assen tegelijk op.

Sla de TLS-wapenwedloop over met de Scraper API

Wanneer het hele probleem uit handen geven

Doe-het-zelf nabootsing werkt totdat het doelwit zijn detectie roteert, een HTTP/2-vingerafdruk toevoegt, of JavaScript-uitvoering vereist — dan onderhoud je een browser-emulatiebibliotheek als een tweede baan. Een Scraper API draagt een echte, roterende browservingerafdruk, komt overeen met de HTTP/2-laag, voert JS op aanvraag uit en retourneert schone HTML, markdown of JSON vanuit één oproep. Het verandert de TLS-wapenwedloop in iemand anders' probleem terwijl jij verder gaat met de data. Voor het bredere beeld van hoe sites automatisering markeren, zie onze gids over elke proxy-detectiesignaal.

Veelgestelde vragen

Wat is een JA3-vingerafdruk?

Een JA3-vingerafdruk is een MD5-hash van vijf velden uit de TLS ClientHello — TLS-versie, cipher suites, extensies, elliptische krommen en puntformaten. Omdat elke softwarestack die velden anders ordent, identificeert de hash de client (Chrome, Firefox, curl, Python) voordat er enige HTTP-data wordt uitgewisseld.

Wat is het verschil tussen JA3 en JA4?

JA3 hasht vijf ClientHello-velden met MD5 en breekt wanneer browsers de volgorde van extensies randomiseren. JA4, van FoxIO, sorteert velden voordat ze worden gehasht zodat het die randomisatie overleeft, voegt een mens-leesbare metadataprefix toe, en dekt QUIC/HTTP/3, ALPN en handtekeningalgoritmen. JA4 is het betrouwbaardere moderne signaal; JA3N is een genormaliseerde tussenoplossing voor JA3.

Kan ik TLS-fingerprinting omzeilen met alleen proxies?

Nee. Proxies veranderen de IP, niet de handshake. Als je TLS-vingerafdruk overeenkomt met een bekende scraping-bibliotheek, helpt het roteren van exits niet — elk verzoek draagt nog steeds de botsignatuur. Je hebt een client nodig die de TLS-stack van een browser reproduceert, en daarbovenop een schone proxy voor IP-reputatie.

Heeft Python requests een detecteerbare TLS-vingerafdruk?

Ja. requests gebruikt urllib3 met een kenmerkende cipher- en extensievolgorde die anti-bot leveranciers hebben gecatalogiseerd, dus zijn JA3 is een bekende botsignatuur. Schakel over naar curl_cffi met een impersonate profiel om een browser-overeenkomende handshake te verzenden.

TLS-fingerprinting verplaatste de strijd onder HTTP, wat de reden is waarom headertrucs en IP-rotatie niet meer voldoende waren op zichzelf. Stem de handshake af, houd de exit schoon, en het 403-op-verzoek-één probleem verdwijnt. Dit is technische begeleiding, geen vergunning om de voorwaarden van een site te negeren — schraap altijd binnen de wet en de regels van het doelwit.

Laat de Scraper API omgaan met JA3, JA4 en HTTP/2