L'empreinte TLS identifie le logiciel qui ouvre une connexion HTTPS en observant comment il l'ouvre — quels chiffrements il propose et dans quel ordre, quelles extensions et courbes elliptiques il liste — avant même l'envoi de tout contenu de requête. Chaque bibliothèque TLS et chaque version de navigateur salue le serveur légèrement différemment, et ce salut est visible en clair par le serveur, même si tout ce qui suit est chiffré. JA3 et son successeur JA4 transforment ce salut en un court hash. Les systèmes anti-bot comparent ce hash à ce que le navigateur prétendu aurait dû produire. C'est pourquoi un script Python se faisant passer pour Chrome, connecté via une IP résidentielle impeccable, est quand même détecté : l'IP disait « utilisateur domestique à Berlin » ; la poignée de main TLS disait « OpenSSL dans un script ».
D'où vient l'empreinte : le ClientHello
Une connexion HTTPS commence par une poignée de main TLS. Le tout premier message, envoyé par le client, est le ClientHello. Il n'est pas chiffré — il ne peut pas l'être, car le chiffrement n'a pas encore été négocié — et il contient, entre autres :
- la version TLS que le client supporte ;
- la liste des suites de chiffrement qu'il est prêt à utiliser, dans son ordre de préférence ;
- une liste d'extensions — SNI (le nom d'hôte), ALPN (les protocoles applicatifs, par ex.
h2,http/1.1), les groupes supportés (courbes elliptiques), les algorithmes de signature, le partage de clé, le ticket de session, etc. — là encore dans un ordre spécifique ; - les courbes elliptiques et formats de points qu'il supporte.
Aucune de ces valeurs n'est secrète et aucune n'est choisie par site ; elles sont intégrées dans la bibliothèque TLS et l'application qui l'utilise. Chrome 128 envoie un ClientHello particulier ; Firefox envoie un autre ; le module ssl de Python (OpenSSL) envoie un troisième ; crypto/tls de Go un quatrième ; curl un cinquième. Le serveur voit le ClientHello de chaque connexion de toute façon — il doit le voir pour y répondre. L'enregistrer et le hacher ne coûte rien.
JA3 et JA4 : transformer la poignée de main en signature
JA3
Introduit par les chercheurs de Salesforce en 2017, JA3 concatène cinq champs du ClientHello — version TLS, suites de chiffrement, extensions, courbes elliptiques, formats de points de courbes elliptiques — sous forme de listes décimales séparées par des virgules, puis hache la chaîne avec MD5. Le résultat est une empreinte de 32 caractères comme cd08e31494f9531f560d64c695473da9. N'importe qui peut la calculer à partir d'une capture de paquets, et des listes mappant les hash JA3 à des clients connus (« ce hash = Chrome 120 sur Windows », « ce hash = python-requests ») sont largement partagées.
JA3 a une faiblesse qui est devenue une fonctionnalité pour l'évasion : parce qu'il hache la liste des extensions dans l'ordre, et que Chrome (depuis la version 110) randomise l'ordre des extensions à chaque connexion, une seule installation de Chrome produit de nombreux hash JA3 différents. Cela a été fait délibérément pour décourager les serveurs de se figer sur une seule empreinte — et cela a rendu JA3 beaucoup moins utile pour identifier les navigateurs.
JA4
JA4, publié par FoxIO en 2023, a été conçu pour survivre à cela. Il trie les listes de chiffrements et d'extensions avant de hacher (donc le mélange de Chrome n'a plus d'importance), conserve certaines parties lisibles par un humain, et intègre plus de signaux : que la connexion soit sur TCP ou QUIC, le type de SNI, la valeur ALPN, la version TLS, et les compteurs de chiffrements et d'extensions. Une empreinte JA4 ressemble à t13d1516h2_8daaf6152771_e5627efa2ab1 : le premier bloc dit « TLS 1.3 sur TCP, 15 chiffrements, 16 extensions, ALPN h2 », les deux autres sont des hash tronqués de la liste triée des chiffrements et de la liste triée des extensions plus les algorithmes de signature. JA4 est en fait une famille (JA4 pour TLS, JA4H pour les en-têtes HTTP, JA4S pour le côté serveur, JA4X pour les certificats, et d'autres) ; lorsque les fournisseurs anti-bot disent « empreinte TLS » aujourd'hui, ils veulent généralement dire JA4 ou un équivalent propriétaire construit de la même manière.
Pourquoi le proxy ne peut pas aider
Un proxy relaie la poignée de main TLS ; il ne la réécrit pas. Avec un proxy HTTP, le client envoie CONNECT host:443, le proxy ouvre un tunnel TCP, et le ClientHello propre du client traverse le tunnel jusqu'à la destination sans être modifié. Avec SOCKS5, la même chose se produit une couche plus bas. Le serveur de destination voit donc deux faits indépendants :
- l'IP source — celle du proxy, résidentielle et irréprochable ;
- le ClientHello — celui du client, indiquant exactement quelle bibliothèque l'a construit.
La logique anti-bot pose alors une question simple : l'empreinte TLS correspond-elle au User-Agent ? L'en-tête User-Agent prétend « Chrome 128 sur Windows ». Le JA4 dit « OpenSSL 3.x via Python ». Un vrai Chrome ne produit jamais ce JA4. La requête est signalée — non pas parce que l'IP est mauvaise, mais parce que l'histoire est incohérente en interne. C'est la raison la plus courante pour laquelle un proxy résidentiel « propre » reçoit encore des CAPTCHA sur des sites protégés, et c'est pourquoi nous disons qu'un proxy répond d'où, pas qui ; voir ce qu'un proxy cache et ne cache pas.
Le proxy peut avoir de l'importance à un égard : certains fournisseurs terminent eux-mêmes TLS (un proxy « man-in-the-middle » qui déchiffre et rechiffre, vous obligeant à installer son certificat). Dans ce cas, la destination voit le ClientHello du proxy, pas le vôtre — ce qui est généralement pire, car c'est une bibliothèque côté serveur, pas un navigateur. Les proxies ordinaires ne font pas cela.
À quoi ressemble chaque type de client
| Client | Ce que dit son empreinte TLS | Cohérent avec un User-Agent de navigateur ? |
|---|---|---|
| Vrai Chrome / Firefox / Safari | Ce navigateur et cette version, sur ce système d'exploitation | Oui — c'est le navigateur |
Python requests, httpx, aiohttp | OpenSSL tel que configuré par le module ssl de Python | Non — reconnaissable comme un script, quels que soient les en-têtes |
Node.js fetch / axios | La version OpenSSL/BoringSSL de Node | Non |
Go net/http | La pile TLS de Go ; distinctive | Non |
| curl (build par défaut) | OpenSSL/LibreSSL tel que compilé | Non |
| Chrome headless via Puppeteer/Playwright | Vrai Chrome — TLS correct | Oui pour TLS ; d'autres signaux (indicateurs d'automatisation, plugins manquants) peuvent encore fuiter |
| Clients « impersonateurs » (curl-impersonate, curl_cffi, tls-client) | Le ClientHello d'un navigateur choisi, reproduit octet par octet | Oui, si vous faites correspondre aussi les en-têtes au même navigateur |
Comment avoir une empreinte cohérente
Il y a trois voies honnêtes, par ordre croissant de coût.
- Utilisez un vrai navigateur. Automatisez Chrome ou Firefox avec Playwright ou Puppeteer ; le TLS est alors réellement celui du navigateur. Plus lent et plus lourd que le HTTP brut, mais pour les sites protégés, c'est la référence. Associez chaque contexte de navigateur à son propre proxy — voir les proxies dans Playwright, Puppeteer et Selenium.
- Utilisez un client HTTP impersonateur. Des bibliothèques comme curl_cffi (Python, basé sur curl-impersonate) et tls-client reproduisent les ClientHello et les paramètres HTTP/2 de navigateurs spécifiques, vous obtenez donc la vitesse d'un scraper avec l'empreinte d'un navigateur. Vous devez alors maintenir tous les autres en-têtes cohérents avec la même version de navigateur — User-Agent,
Accept-Language, indices clientsec-ch-ua— sinon vous échangez une contradiction contre une autre. Notre guide des proxies Python montre le passage derequestsàcurl_cffi. - Arrêtez de faire semblant. Si une cible offre une API officielle, utilisez-la avec votre véritable identité de client. L'empreinte TLS n'est un problème que lorsque l'empreinte contredit la revendication.
Ce qui ne fonctionne pas : définir un User-Agent Chrome sur requests. Cela change un en-tête et laisse la poignée de main intacte — l'incohérence est maintenant plus flagrante qu'avant, car un UA python-requests simple avec une empreinte OpenSSL est au moins cohérent en soi.
La vue d'ensemble : les empreintes s'empilent
TLS est une couche. Les fournisseurs anti-bot modernes identifient également la connexion HTTP/2 (valeurs de la trame SETTINGS, tailles de fenêtre, ordre des en-têtes et des pseudo-en-têtes — parfois appelée empreinte Akamai), la pile TCP/IP (taille de fenêtre, TTL, options ; p0f classique), et bien sûr le navigateur lui-même via JavaScript, qu'un client HTTP ne peut pas exécuter du tout. Chaque couche doit raconter la même histoire que les autres et que l'IP. Une IP résidentielle avec une empreinte TLS de navigateur et des paramètres HTTP/2 de navigateur mais sans exécution de JavaScript reste une anomalie sur un site qui s'attend à ce que le défi JS soit exécuté. C'est pourquoi la réponse honnête à « quel proxy évite la détection ? » est « aucun par lui-même » — et pourquoi nos classements pèsent ce que le fournisseur fait au-delà de l'IP ; voir la comparaison des proxies élite.
Comment voir votre propre empreinte
Plusieurs pages publiques renvoient le JA3/JA4 qu'elles calculent pour votre connexion, ainsi que le navigateur auquel elles pensent qu'il appartient. Chargez-en une depuis un vrai navigateur, puis récupérez-la avec votre script via le même proxy, et comparez. Si les deux diffèrent, vous avez trouvé la raison pour laquelle votre script est traité différemment de votre navigateur — et aucun changement de proxy ne résoudra cela. Ajoutez ceci aux vérifications de Comment tester un proxy chaque fois que la cible est connue pour utiliser un anti-bot d'entreprise.
Questions fréquemment posées
Qu'est-ce que JA3 ?
Un hash MD5 de cinq champs du ClientHello TLS (version, chiffrements, extensions, courbes, formats de points) utilisé pour identifier le logiciel client. Il fonctionne bien pour les scripts et les bibliothèques ; il est devenu peu fiable pour Chrome depuis que Chrome a commencé à randomiser l'ordre des extensions.
Qu'est-ce que JA4 ?
Le successeur de JA3 : il trie les listes avant de hacher afin que le mélange des extensions ne le change pas, conserve une partie de l'empreinte lisible, et inclut le transport (TCP/QUIC), l'ALPN et les compteurs. C'est la base de la plupart des détections actuelles d'empreintes TLS.
Un proxy résidentiel change-t-il mon empreinte TLS ?
Non. Le proxy tunnelise votre poignée de main sans modification ; la destination voit l'IP du proxy et votre ClientHello. Seul le logiciel client détermine l'empreinte.
Puis-je falsifier l'empreinte TLS d'un navigateur en Python ?
Oui, avec des clients impersonateurs comme curl_cffi, qui reproduisent le ClientHello et le comportement HTTP/2 d'un navigateur choisi. Vous devez garder les en-têtes cohérents avec le même navigateur. Les requests/httpx simples ne peuvent pas faire cela.
L'empreinte TLS est-elle la même chose que l'empreinte du navigateur ?
Non. L'empreinte TLS lit la poignée de main de la connexion chiffrée et identifie le logiciel client ; l'empreinte du navigateur exécute JavaScript et identifie l'appareil (canvas, polices, GPU). Les systèmes anti-bot utilisent les deux, plus la réputation de l'IP, et vérifient qu'ils concordent.
Pourquoi le même script est-il bloqué sur un site et pas sur un autre ?
Parce que les vérifications d'empreinte TLS sont une fonctionnalité des produits anti-bot d'entreprise, pas du web en général. Les sites sans cette protection ne regardent jamais la poignée de main ; les sites avec cette protection la comparent au User-Agent à chaque requête.