Avertissement légal : Cet article s'adresse aux chercheurs en sécurité et ingénieurs de scraping effectuant une automatisation autorisée ou accédant à des données publiques. L'accès non autorisé à des systèmes protégés peut violer le Computer Fraud and Abuse Act (CFAA) aux États-Unis ou le RGPD en Europe. Ne contournez jamais un contrôle d'accès pour usurper des identifiants, accéder à des données privées, ou violer les conditions d'utilisation d'un site. Les techniques décrites ici visent à comprendre comment Turnstile évalue la confiance, pas à le briser.
Si vous avez déjà vu une page se charger, puis afficher subitement « Vérification que vous êtes humain » pendant 3 à 8 secondes, vous avez rencontré Turnstile. Pour les ingénieurs de scraping et les chercheurs en sécurité, comprendre les internes de Cloudflare Turnstile n'est pas un exercice académique : c'est la différence entre une collecte de données fiable et un taux d'échec de 90 %.
En 2026, Turnstile ne repose plus sur un simple CAPTCHA visuel. Il exécute une suite de défis invisibles — preuve de travail, sondes d'API navigateur, collecte d'empreintes TLS et HTTP/2 — puis combine ces signaux avec la réputation IP pour produire un score de confiance. Le token cf_clearance qui en résulte est strictement lié à votre User-Agent et à votre adresse IP. Changer l'un invalide l'autre.
Cet article démonte chaque couche du pipeline, explique pourquoi un client Python avec un JA4 Chrome est détecté instantanément, et montre une approche légitime utilisant des sessions résidentielles sticky ProxyHat avec un vrai navigateur.
Comment fonctionnent les internes de Cloudflare Turnstile
Turnstile est un widget JavaScript embarqué dans des millions de sites. Quand la page se charge, le script de défi géré (documentation officielle Turnstile) télécharge un payload obfusqué depuis challenges.cloudflare.com et exécute une série de tests dans le navigateur. Le processus comprend :
- Preuve de travail (Proof-of-Work) : le navigateur doit résoudre un hash partiel — typiquement quelques milliers d'itérations SHA-256 — dont la difficulté s'ajuste dynamiquement selon le score de risque initial. Un navigateur légitime résout cela en 200–800 ms ; un script sans moteur JavaScript complet échoue ou met trop de temps.
- Sondes d'API navigateur : le script teste la présence et le comportement de dizaines d'API —
navigator.webdriver,window.chrome,navigator.permissions,WebGLRenderingContext,AudioContext,RTCPeerConnection. Chaque API absente ou incohérente avec l'User-Agent déclaré augmente le score de risque. - Collecte d'empreintes comportementales : mouvements de souris, frappe clavier, événements tactiles, vitesse de défilement. Les humains produisent des courbes irrégulières ; les bots produisent des lignes droites ou des intervalles parfaitement réguliers.
- Émission du token : si tous les signaux passent, Turnstile renvoie un token au serveur d'origine, qui appelle l'API
/siteverifyde Cloudflare. Le serveur d'origine décide ensuite d'émettrecf_clearance.
Le cookie cf_clearance est le sésame. Une fois obtenu, il évite de repasser le défi pendant sa durée de validité — généralement 30 minutes à 24 heures selon la configuration du site. Mais ce token n'est pas portable : il est cryptographiquement lié à deux éléments.
Lien entre cf_clearance, User-Agent et IP
Le cookie cf_clearance contient un HMAC signé par Cloudflare qui inclut :
- L'User-Agent exact présenté lors du défi.
- L'adresse IP source observée par le proxy Cloudflare.
Si vous obtenez cf_clearance avec l'IP 203.0.113.42 et l'UA Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..., toute requête ultérieure doit présenter exactement la même paire IP + UA. Changer l'IP — même d'un seul octet — provoque un 403 Forbidden avec le code d'erreur 1020. C'est pourquoi le choix du proxy est critique.
Le score de confiance à quatre signaux de Bot Management
Derrière Turnstile se trouve Cloudflare Bot Management, qui calcule un score de confiance sur 100 en combinant quatre familles de signaux. Un score inférieur à un seuil configurable (souvent 10–30) déclenche le défi géré ; un score très bas déclenche un blocage direct.
1. Empreinte TLS JA4
JA4 est la quatrième génération d'empreintes TLS, introduite par FoxIO et désormais intégrée dans les produits de détection. Contrairement à JA3 qui concaténait les extensions dans l'ordre du client, JA4 trie les extensions par valeur hexadécimale avant de hacher, ce qui élimine les variations d'ordre entre implémentations TLS et produit un hash stable par client.
Le format JA4 est : q13d1516h2_8daaf6152771_b186095e22b3 où :
q13d1516h2encode la version TLS (1.3), le nombre de cipher suites (15), le nombre d'extensions (16), et les algorithmes de signature (h2 = 2).- Le premier hash capture les cipher suites triées.
- Le second hash capture les extensions triées.
Chrome 120+ sur Windows produit un JA4 spécifique. Firefox en produit un autre. curl et requests (via OpenSSL) produisent un JA4 totalement différent. Cloudflare maintient une base de correspondances JA4 ↔ navigateur déclaré. Si votre User-Agent dit « Chrome » mais votre JA4 est celui d'OpenSSL, le score de confiance chute immédiatement.
2. Paramètres HTTP/2 SETTINGS
Au-delà de TLS, Cloudflare inspecte la trame SETTINGS HTTP/2 envoyée avant la première requête. Chaque navigateur envoie un ordre et des valeurs de paramètres distincts :
- Chrome envoie SETTINGS avec
INITIAL_WINDOW_SIZE = 6291456,MAX_HEADER_LIST_SIZE = 262144, etENABLE_PUSH = 0dans un ordre précis. - Firefox utilise des valeurs et un ordre différents.
- Python httpx / hyper produisent un ordre de SETTINGS qui ne correspond à aucun navigateur réel.
Cette couche est invisible pour la plupart des développeurs mais trahit immédiatement un client non-navigateur.
3. Empreinte du navigateur (canvas, WebGL, audio)
Le JavaScript de Turnstile collecte des empreintes côté client :
- Canvas fingerprint : le rendu d'une image de test sur
<canvas>produit un hash unique selon le GPU, le pilote graphique, et l'anti-aliasing. Deux machines identiques peuvent produire des hashes légèrement différents ; un navigateur headless sans GPU produit un hash reconnaissable. - WebGL fingerprint :
WEBGL_debug_renderer_infoexpose le vendor et le renderer GPU (ANGLE (NVIDIA, NVIDIA GeForce RTX 4070...)). Un environnement headless sans GPU renvoieSwiftShaderouMesa, ce qui est un signal fort d'automatisation. - Audio fingerprint :
OfflineAudioContextgénère un hash à partir du traitement du signal audio. Les environnements sans carte son produisent un hash distinct.
4. Réputation IP
Cloudflare classe chaque IP source selon son type et son historique :
| Type d'IP | Score de réputation | Probabilité de défi |
|---|---|---|
| Résidentielle (FAI réel) | Élevé | Faible à modéré |
| Mobile (opérateur 4G/5G) | Très élevé | Très faible |
| Datacenter (AWS, OVH, Hetzner) | Faible à très faible | Élevé à systématique |
| VPN/Proxy connu | Très faible | Systématique |
Une IP datacenter avec un JA4 Chrome parfait et un canvas fingerprint légitime sera quand même défiée, parce que la réputation IP pèse lourd dans le score global.
Pourquoi une connexion Python avec un JA4 Chrome est détectée instantanément
Beaucoup d'ingénieurs tentent de forger un JA4 Chrome avec des bibliothèques comme curl-impersonate ou cycletls. Ces outils réordonnent les cipher suites et les extensions TLS pour correspondre à Chrome. Mais ils ne résolvent qu'une couche sur quatre.
Voici ce qui se passe quand un client Python curl-impersonate frappe un site protégé par Turnstile :
- JA4 : passe — correspond à Chrome.
- HTTP/2 SETTINGS : échec partiel — l'ordre des paramètres peut différer subtilement de Chrome réel.
- Empreinte navigateur : échec total — il n'y a pas de canvas, pas de WebGL, pas d'AudioContext. Le script de défi ne peut même pas s'exécuter.
- Réputation IP : si datacenter, score bas.
Le score combiné est si bas que Turnstile ne propose même pas le défi : la réponse est un 403 direct. C'est pourquoi forger un JA4 seul ne suffit pas. Les quatre signaux doivent être cohérents et l'IP doit avoir une bonne réputation.
Pourquoi les proxies résidentiels sont indispensables pour cf_clearance
Le cookie cf_clearance est épinglé à l'IP. Cela crée deux contraintes majeures :
1. L'IP doit être résidentielle pour passer le défi. Une IP datacenter est immédiatement classée comme suspecte. Même si votre navigateur est parfait, le score de réputation IP peut suffire à déclencher le défi géré ou un blocage.
2. L'IP doit rester constante pendant toute la session. Si vous obtenez cf_clearance avec l'IP 203.0.113.42 puis votre proxy rotatif vous attribue 198.51.100.7 pour la requête suivante, le cookie est rejeté. Vous devez repasser le défi — et les défis successifs depuis des IP différentes augmentent le score de risque, pouvant mener à un blocage permanent.
C'est pourquoi une session sticky sur une IP résidentielle stable est la seule approche viable. La rotation par requête — utile pour d'autres scénarios de scraping — est contre-productive avec Turnstile.
Approche pratique : sessions résidentielles sticky ProxyHat + vrai navigateur
Voici une approche légitime pour accéder à des données publiques derrière Turnstile, en utilisant ProxyHat avec une session résidentielle sticky et un vrai navigateur.
Étape 1 : Obtenir une session résidentielle sticky
Avec ProxyHat, vous créez une session sticky en ajoutant -session-abc123 au nom d'utilisateur. Tant que vous réutilisez le même identifiant de session, ProxyHat vous attribue la même IP de sortie.
# ProxyHat residential sticky session (HTTP)
export PROXY_URL="http://user-session-abc123-country-US:pass@gate.proxyhat.com:8080"
curl -x "$PROXY_URL" https://httpbin.org/ip
Pour SOCKS5, utilisez le port 1080 :
# ProxyHat residential sticky session (SOCKS5)
export PROXY_URL="socks5://user-session-abc123-country-US:pass@gate.proxyhat.com:1080"
Consultez la liste des localisations ProxyHat pour cibler un pays spécifique.
Étape 2 : Lancer un vrai navigateur via le proxy
Utilisez Playwright ou Puppeteer avec un navigateur Chromium non-headless (ou headless avec --headless=new et des flags de stealth). Le navigateur doit passer le défi Turnstile pour obtenir cf_clearance.
from playwright.sync_api import sync_playwright
proxy_config = {
"server": "http://gate.proxyhat.com:8080",
"username": "user-session-abc123-country-US",
"password": "pass"
}
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False,
proxy=proxy_config,
args=["--disable-blink-features=AutomationControlled"]
)
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"
)
page = context.new_page()
page.goto("https://exemple-protege.com")
page.wait_for_timeout(8000) # laisser Turnstile s'exécuter
# Récupérer cf_clearance
cookies = context.cookies()
cf_clearance = next(
(c for c in cookies if c["name"] == "cf_clearance"), None
)
if cf_clearance:
print(f"cf_clearance obtenu : {cf_clearance['value'][:20]}...")
browser.close()
Étape 3 : Réutiliser cf_clearance avec des requêtes HTTP
Une fois le cookie obtenu, vous pouvez l'utiliser avec httpx ou requests — tant que vous passez par la même IP résidentielle et le même User-Agent.
import httpx
proxy_url = "http://user-session-abc123-country-US:pass@gate.proxyhat.com:8080"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Cookie": f"cf_clearance={cf_clearance_value}"
}
with httpx.Client(proxy=proxy_url, headers=headers, http2=True) as client:
resp = client.get("https://exemple-protege.com/data")
print(resp.status_code, resp.text[:200])
Important : le httpx standard ne reproduit pas le JA4 de Chrome ni les SETTINGS HTTP/2 de Chrome. Pour les sites les plus stricts, continuez à utiliser le navigateur pour toutes les requêtes. Pour les sites modérés, httpx avec le bon cookie + IP + UA peut suffire car cf_clearance court-circuite le défi.
Étape 4 : Gérer l'expiration du cookie
Le cookie cf_clearance expire. Surveillez les réponses 403 avec le code 1020 — c'est le signal que le cookie a expiré ou que l'IP a changé. Implémentez une logique de renouvellement :
import time
def fetch_with_renewal(url, max_retries=3):
for attempt in range(max_retries):
resp = make_request(url)
if resp.status_code == 403:
# Renouveler cf_clearance via le navigateur
cf_clearance_value = renew_clearance()
time.sleep(2)
continue
return resp
raise Exception("Échec après renouvellement")
Erreurs courantes et cas limites
Erreur 1 : Rotation d'IP après obtention du cookie
Le piège classique : on lance le navigateur avec une IP, on obtient cf_clearance, puis on utilise un proxy rotatif pour les requêtes suivantes. Résultat : 100 % de 403. La session sticky ProxyHat (-session-abc123) garantit que la même IP est utilisée du début à la fin.
Erreur 2 : User-Agent incohérent
Le navigateur obtient le cookie avec un UA Chrome Windows. Les requêtes suivantes utilisent un UA différent — même un autre Chrome, mais sur macOS. Le cookie est rejeté. L'UA doit être identique au caractère près.
Erreur 3 : Headless détecté
Chrome headless classique expose navigator.webdriver = true et window.chrome incomplet. Utilisez --headless=new (Chrome 112+) ou un navigateur non-headless via Xvfb. Les bibliothèques comme undetected-chromedriver ou playwright-stealth patchent ces signaux.
Erreur 4 : JA4 incohérent entre navigateur et client HTTP
Si vous passez du navigateur à httpx, le JA4 change. Pour les sites qui vérifient la cohérence du JA4 sur toutes les requêtes (et pas seulement au moment du défi), restez sur le navigateur. Consultez la documentation ProxyHat pour plus de détails sur la configuration des sessions.
Cas limite : Turnstile en mode interact
Si le score de risque est très élevé, Turnstile peut basculer en mode interactif — une case à cocher « Je suis humain » ou un puzzle. Ce mode ne peut pas être passé automatiquement de manière fiable. C'est un signal que votre IP ou votre comportement est trop suspect ; changez d'IP résidentielle ou réduisez la fréquence de requêtes.
Comparaison : types de proxies face à Turnstile
| Type de proxy | Réputation IP | Stabilité de session | Adapté à Turnstile |
|---|---|---|---|
| Datacenter rotatif | Très faible | Faible (IP change) | Non |
| Datacenter sticky | Faible | Élevée | Non — réputation trop basse |
| Résidentiel rotatif | Élevée | Faible (IP change) | Non — cf_clearance invalidé |
| Résidentiel sticky | Élevée | Élevée (IP constante) | Oui — approche recommandée |
| Mobile sticky | Très élevée | Élevée | Oui — meilleure réputation |
Le proxy résidentiel sticky offre le meilleur équilibre coût/efficacité. Le proxy mobile sticky est encore meilleur mais plus rare et plus coûteux. Consultez la page de tarification ProxyHat pour comparer les options.
Quand cette approche est appropriée
Légitimité avant tout. Cette technique est appropriée pour :
- Accès à des données publiques derrière Turnstile : prix publics, résultats de recherche, données gouvernementales ouvertes.
- Recherche en sécurité autorisée : tests d'intrusion avec autorisation écrite du propriétaire du site.
- Automatisation de vos propres comptes sur des plateformes où vous avez un compte légitime et où l'automatisation est permise par les conditions d'utilisation.
- Monitoring de disponibilité de vos propres services protégés par Cloudflare.
Cette approche n'est jamais appropriée pour :
- Usurpation de comptes ou credential stuffing.
- Contournement de paywalls ou de restrictions d'accès payantes.
- Scalping de billets ou de sneakers en violation des conditions d'utilisation.
- Attaques DDoS ou épuisement de ressources.
Le Computer Fraud and Abuse Act (CFAA) aux États-Unis criminalise l'accès non autorisé à des systèmes protégés. En Europe, le RGPD peut s'appliquer si les données collectées sont personnelles. Évaluez toujours la légalité de votre cas d'usage avant de déployer.
Points clés à retenir
Turnstile est un système à quatre couches. JA4 TLS, SETTINGS HTTP/2, empreinte navigateur (canvas/WebGL/audio), et réputation IP. Forger une seule couche ne suffit pas — les quatre doivent être cohérentes avec un vrai navigateur sur une IP de bonne réputation.
- cf_clearance est épinglé à IP + User-Agent. Changer l'un invalide l'autre. La session sticky ProxyHat (
-session-abc123) est obligatoire. - Les IP datacenter sont quasi-systématiquement défiées. Utilisez des proxies résidentiels ou mobiles pour maximiser le score de confiance.
- Un vrai navigateur est nécessaire pour le défi initial. Le JavaScript de Turnstile ne s'exécute pas dans
requestsoucurl. Utilisez Playwright/Puppeteer avec stealth. - Surveillez l'expiration.
cf_clearancedure 30 min à 24 h. Implémentez un renouvellement automatique. - Vérifiez la légalité. CFAA et RGPD s'appliquent. N'utilisez ces techniques que pour un accès autorisé ou des données publiques.
Pour aller plus loin sur l'intégration de proxies dans vos pipelines de scraping, consultez nos cas d'usage sur le web scraping et le suivi SERP.






