Internals di Cloudflare Turnstile: cosa viene eseguito davvero
Quando un client richiede una pagina protetta da Cloudflare Turnstile, non riceve solo un widget visibile. Dietro le quinte, il managed-challenge di Cloudflare carica un payload JavaScript offuscato che esegue una serie di probe sul browser, raccoglie segnali crittografici a livello TLS e calcola un trust score prima ancora che l'utente veda un checkbox. Per chi fa automazione legittima — scraping di dati pubblici, QA autorizzato, ricerca di sicurezza — capire questi internals di Cloudflare Turnstile è la differenza tra una pipeline che gira per ore e una che muore dopo 3 richieste.
Il sistema si basa su quattro pilastri: (1) il JavaScript di challenge gestito, che esegue proof-of-work e probe delle API del browser; (2) il cookie cf_clearance, strettamente legato a User-Agent e IP del client; (3) il trust score a quattro segnali che combina JA4, HTTP/2 SETTINGS, fingerprint del browser e reputazione IP; (4) la decisione finale — allow, managed challenge, interactive challenge o block. Il Bot Management di Cloudflare non è un singolo check ma una pipeline di segnali correlati.
Avviso legale: questa guida è per automazione autorizzata, ricerca di sicurezza con consenso e accesso a dati pubblici. L'elusione di controlli anti-bot su siti di terzi senza autorizzazione può violare i Termini di Servizio, il CFAA negli Stati Uniti o normative GDPR/DSA in Europa. Non usare queste tecniche per credential stuffing, frode o accesso non autorizzato.
Perché il problema esiste: il contesto tecnico
Cloudflare protegge circa il 20% di tutti i siti web nel 2025-2026. I bot generano oltre il 40% del traffico Internet globale, e una frazione significativa di questi è malevolo — credential stuffing, scraping aggressivo, DDoS applicativi. Turnstile è la risposta di Cloudflare al reCAPTCHA di Google, ma con una differenza fondamentale: è progettato per essere invisibile nella maggior parte dei casi. L'utente legittimo non vede nulla; il bot viene sfidato o bloccato.
Il problema per l'automazione legittima è che i browser headless — anche con patch di stealth — spesso non passano il trust score iniziale. Questo accade perché i segnali che Cloudflare raccoglie sono multi-livello: un browser può avere il JavaScript corretto ma presentare un JA4 TLS che non corrisponde a nessun browser reale, oppure avere un fingerprint canvas perfetto ma un IP datacenter noto. La pipeline di detection è defence in depth: ogni segnale deve essere coerente con gli altri.
Cosa Turnstile esegue realmente: il challenge JavaScript
Il payload di Turnstile è distribuito tramite challenges.cloudflare.com e caricato in un iframe o inline. Il codice è pesantemente offuscato e cambia frequentemente, ma i probe che esegue sono categorizzabili:
Proof-of-Work (PoW)
Turnstile assegna al client un problema crittografico — tipicamente un hash parziale (trovare un nonce tale che SHA-256(challenge || nonce) abbia un certo numero di zeri iniziali). La difficoltà è dinamica: un client con trust score alto riceve un PoW trivial (millisecondi), uno sospetto riceve un PoW che richiede 2-5 secondi di calcolo. Questo penalizza i bot che fanno migliaia di richieste al secondo, ma è trasparente per un browser reale.
Probe delle API del browser
Il JavaScript interroga decine di API per verificare la coerenza dell'ambiente:
- navigator.userAgent vs navigator.userAgentData (Client Hints): se un browser dice Chrome 120 ma non espone
uaData.brands, è sospetto. - navigator.webdriver: se
true, il client è un'istanza automatizzata di ChromeDriver. - navigator.plugins e navigator.mimeTypes: i browser reali hanno plugin predefiniti; Puppeteer di default ne ha zero.
- window.chrome: l'oggetto
window.chromedeve esistere in Chrome reale con una struttura specifica (runtime, app, csi). - screen.width, screen.height, devicePixelRatio: devono essere coerenti con il viewport dichiarato.
- performance.now() resolution: browser reali restituiscono microsecondi; alcuni headless restituiscono millisecondi.
Fingerprint Canvas, WebGL e Audio
Turnstile raccoglie fingerprint hardware-level che sono estremamente difficili da falsificare in modo coerente:
- Canvas fingerprint: rendering di testo e forme su un elemento
<canvas>e hashing dei pixel risultanti. Varia per GPU, driver e sistema operativo. Due macchine diverse producono hash diversi. - WebGL fingerprint:
WEBGL_debug_renderer_infoespone il vendor e il renderer della GPU (es.Google Inc. (NVIDIA)vsGoogle SwiftShader). SwiftShader è il renderer software usato da molti headless — un segnale immediato. - Audio fingerprint: un
OfflineAudioContextprocessa un oscillator e misura il risultato floating-point. Varia per CPU e implementazione audio. I browser headless spesso producono un fingerprint identico a tutti gli altri headless.
Il punto chiave è che questi fingerprint non sono singoli valori da spoofare, ma una matrice di coerenza. Se dichiari Chrome 120 su Windows 11 ma il canvas fingerprint corrisponde a un Linux con Mesa, il trust score crolla.
Il cookie cf_clearance e il suo binding
Quando un client supera il challenge, Turnstile emette un cookie cf_clearance con scadenza tipica di 30 minuti. Questo cookie è crittograficamente legato a due fattori:
- L'IP da cui il challenge è stato completato.
- Lo User-Agent presentato durante il challenge.
Se uno di questi cambia, il cookie viene rifiutato alla richiesta successiva. Questo è il motivo per cui un proxy che ruota IP ad ogni richiesta rende impossibile il riutilizzo di cf_clearance: il token è stato mintato sull'IP A, ma la richiesta arriva dall'IP B.
Il trust score a quattro segnali
Il motore di Bot Management assegna un punteggio da 1 a 99 (o una classificazione categorica) basandosi su quattro segnali principali. Vediamoli in dettaglio.
1. JA4 — il fingerprint TLS
JA4 è il successore di JA3, introdotto da FoxIO nel 2023 e adottato da Cloudflare. A differenza di JA3, JA4 ordina le estensioni prima di fare l'hash, rendendo il fingerprint deterministico e indipendente dall'ordine di invio. Il formato è:
JA4 = t(tver)(cipher_count)(extension_count)(hash(ciphers_sorted)(extensions_sorted))
Ad esempio, un Chrome 120 reale su Windows produce un JA4 come t13d1516h2_8daaf6152771_b186095e22b6, mentre le librerie Python requests con urllib3 producono un JA4 completamente diverso come t13d1716h2_4d7e0d6c2b32_8c1a1b2d3e4f. La differenza è nelle estensioni: Chrome include application_settings, renegotiation_info e signed_certificate_timestamp in un ordine specifico; Python non le include o le include in ordine diverso.
Cloudflare mantiene un database di JA4 noti per ogni browser e versione. Se un client dichiara User-Agent: Mozilla/5.0 ... Chrome/120.0.0.0 ma presenta un JA4 che corrisponde a Python-urllib3/2.1.0, il trust score viene impostato al minimo e il client riceve un managed challenge immediato.
2. HTTP/2 SETTINGS frame
Oltre al JA4, Cloudflare ispeziona il frame SETTINGS di HTTP/2. Ogni client HTTP/2 invia un frame SETTINGS con parametri come HEADER_TABLE_SIZE, ENABLE_PUSH, MAX_CONCURRENT_STREAMS, INITIAL_WINDOW_SIZE, MAX_FRAME_SIZE, MAX_HEADER_LIST_SIZE. I valori predefiniti variano tra implementazioni:
| Client | HEADER_TABLE_SIZE | INITIAL_WINDOW_SIZE | MAX_FRAME_SIZE |
|---|---|---|---|
| Chrome 120 | 65536 | 6291456 | 16384 |
| Firefox 121 | 65536 | 131072 | 16384 |
| Python httpx/h2 | 4096 | 65535 | 16384 |
| Node.js (http2) | 4096 | 65535 | 16384 |
Questi valori sono un fingerprint supplementare. Anche se un client corregge il JA4, se il frame SETTINGS non corrisponde al browser dichiarato, il trust score viene penalizzato.
3. Fingerprint del browser (canvas/WebGL/audio)
Come discusso sopra, il JavaScript di Turnstile raccoglie fingerprint hardware. Il punto importante è che questi fingerprint sono stabili per macchina ma incoerenti tra ambienti simulati. Un browser headless su un server Linux produce fingerprint che non corrispondono a nessun profilo Chrome reale su Windows o macOS.
4. Reputazione IP
L'IP da cui arriva la richiesta viene valutato contro database di reputazione che includono:
- ASN datacenter (AWS, GCP, Azure, DigitalOcean) — penalità automatica.
- ASN residenziali (Comcast, AT&T, Vodafone, Telecom Italia) — punteggio neutro o positivo.
- IP segnalati per abuso in feed pubblici (Spamhaus, AbuseIPDB).
- IP associati a botnet note.
- Velocità di richieste dall'IP nell'ultima ora.
Un IP datacenter con un JA4 perfetto e un fingerprint browser coerente può comunque ricevere un managed challenge, semplicemente perché l'ASN è AS14061 (DigitalOcean). Un IP residenziale con gli stessi segnali passa pulito.
Perché una connessione Chrome-dichiarata ma Python-JA4 viene sfidata all'istante
Questo è lo scenario più comune per chi fa scraping con requests o httpx. Il flusso è:
- Il client invia un
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ... Chrome/120.0.0.0. - Il TLS handshake presenta un JA4 che corrisponde a
Python/3.11 + urllib3, non a Chrome. - Cloudflare confronta il JA4 osservato con il JA4 atteso per il browser dichiarato nell'User-Agent.
- Mismatch → trust score basso → managed challenge o block.
La correzione naive — usare una libreria come curl_cffi o tls-client che impersona il JA4 di Chrome — risolve il TLS ma non risolve il fingerprint del browser (canvas, WebGL, audio) né il frame SETTINGS HTTP/2. Cloudflare vede ancora incoerenza. La soluzione robusta è usare un browser reale — Playwright o Puppeteer con un profilo Chrome autentico — che produce tutti i segnali corretti per costruzione.
Perché i proxy residenziali sono essenziali per cf_clearance
Il cookie cf_clearance è IP-pinned. Questo significa che:
- Ottieni il cookie dall'IP
203.0.113.42(un residenziale). - Usi il cookie dalla stessa IP per le richieste successive.
- Se l'IP cambia (rotazione, dropout del proxy), il cookie viene rifiutato e devi rifare il challenge.
I proxy datacenter hanno due problemi qui: (1) la reputazione IP bassa significa che il challenge iniziale è più difficile (PoW più alto, challenge interattivo); (2) anche se ottieni il cookie, l'IP datacenter è più probabile che venga flaggato retroattivamente. I proxy residenziali, invece, offrono un IP che Cloudflare vede come un utente domestico reale, con trust score iniziale più alto.
La chiave è usare sessioni sticky: lo stesso IP di uscita per tutta la durata della sessione di scraping. Con ProxyHat, questo si ottiene con un flag -session- nel username:
http://user-session-abc123:pass@gate.proxyhat.com:8080
Finché la sessione abc123 è attiva, tutte le richieste escono dallo stesso IP residenziale. Questo permette di ottenere cf_clearance una volta e riutilizzarlo per decine o centinaia di richieste successive.
Approccio pratico: ottenere e riutilizzare cf_clearance con ProxyHat
Vediamo un'implementazione legittima: scraping di dati pubblici da un sito protetto da Turnstile, usando un browser reale via Playwright e proxy residenziali sticky di ProxyHat.
Step 1: Configurare il proxy sticky in Playwright
from playwright.sync_api import sync_playwright
import json, pickle
PROXY = {
"server": "http://gate.proxyhat.com:8080",
"username": "user-session-scrape001",
"password": "pass"
}
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False, # headful per fingerprint reali
proxy=PROXY
)
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",
viewport={"width": 1920, "height": 1080}
)
page = context.new_page()
page.goto("https://example-protected-site.com")
# Attendi che Turnstile risolva il challenge
page.wait_for_timeout(10000)
# Estrai i cookie
cookies = context.cookies()
cf_clearance = [c for c in cookies if c["name"] == "cf_clearance"]
if cf_clearance:
with open("cf_clearance.pkl", "wb") as f:
pickle.dump({
"cookie": cf_clearance[0],
"user_agent": "Mozilla/5.0 ... Chrome/120.0.0.0",
"proxy_session": "scrape001"
}, f)
print("cf_clearance ottenuto!")
browser.close()
Step 2: Riutilizzare cf_clearance con richieste successive
Una volta ottenuto il cookie, puoi usarlo con curl o una libreria HTTP — ma devi mantenere lo stesso IP e lo stesso User-Agent:
curl -x http://user-session-scrape001:pass@gate.proxyhat.com:8080 \
-H "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" \
-H "Cookie: cf_clearance=TOKEN_VALUE_HERE" \
"https://example-protected-site.com/api/data"
Con Python e requests, mantenendo la stessa sessione proxy:
import requests, pickle
with open("cf_clearance.pkl", "rb") as f:
data = pickle.load(f)
proxies = {
"http": "http://user-session-scrape001:pass@gate.proxyhat.com:8080",
"https": "http://user-session-scrape001:pass@gate.proxyhat.com:8080"
}
headers = {
"User-Agent": data["user_agent"],
"Cookie": f"cf_clearance={data['cookie']['value']}"
}
resp = requests.get(
"https://example-protected-site.com/api/data",
proxies=proxies,
headers=headers
)
print(resp.status_code, resp.json())
Step 3: Gestire la scadenza del cookie
Il cookie cf_clearance scade dopo circa 30 minuti. La strategia raccomandata è:
- Monitorare le risposte 403/503 — indicano che il cookie è scaduto o invalidato.
- Ri-eseguire il flow di Playwright per ottenere un nuovo cookie quando necessario.
- Mantenere la stessa sessione proxy (
-session-scrape001) per evitare di cambiare IP.
Consulta la documentazione di ProxyHat per dettagli sulle sessioni sticky e sulla rotazione controllata.
Errori comuni e casi limite
Errore 1: Cambiare User-Agent tra challenge e richieste
Il cookie cf_clearance è legato all'User-Agent. Se ottieni il cookie con Chrome 120 e poi fai richieste con un User-Agent Firefox, il cookie viene rifiutato. Mantieni lo stesso UA per tutta la sessione.
Errore 2: Usare un browser headless senza stealth
Puppeteer e Playwright in modalità headless default espongono navigator.webdriver = true e non hanno window.chrome. Usa headless=False o patch di stealth come playwright-stealth. Meglio ancora: usa un browser Chromium con flag --disable-blink-features=AutomationControlled.
Errore 3: Proxy datacenter per ottenere cf_clearance
Un IP datacenter può ricevere un challenge interattivo (checkbox visibile) invece di uno invisibile. Questo rallenta l'automazione e, in alcuni casi, rende impossibile l'ottenimento del cookie in modo programmatico. Usa sempre proxy residenziali per il challenge iniziale.
Errore 4: Rotazione IP durante la sessione
Se il tuo provider proxy ruota IP ogni richiesta (backconnect rotating), cf_clearance sarà valido solo per la prima richiesta. Usa sessioni sticky con durata sufficiente (30-60 minuti). Con ProxyHat, il flag -session- mantiene lo stesso IP finché la sessione è attiva.
Caso limite: sfide interattive e hCaptcha fallback
In alcuni casi, Cloudflare può richiedere un challenge interattivo (CAPTCHA) anche per IP residenziali — ad esempio se il sito ha regole Bot Management molto aggressive o se il pattern di richieste è chiaramente bot-like (1000 richieste in 10 secondi dallo stesso IP). In questi casi, nessuna quantità di fingerprint corretto aiuta: devi rallentare, distribuire le richieste su più sessioni proxy e rate-limitare.
Quando questo approccio è appropriato
Le tecniche descritte sono appropriate per:
- Scraping di dati pubblici — pagine accessibili senza login, dati non coperti da copyright o ToS restrittive.
- QA e testing autorizzato — testare il proprio sito o un sito su cui si ha autorizzazione esplicita.
- Ricerca di sicurezza — analisi di comportamenti anti-bot con scopo accademico o difensivo.
- Monitoraggio di prezzi e SERP — dati pubblici per intelligence di mercato.
Non è appropriato per:
- Credential stuffing o brute-force.
- Accesso a contenuti dietro paywall o login non autorizzato.
- Scraping di dati personali coperti da GDPR senza base legale.
- Attività che violano i Termini di Servizio del sito target.
Consulta le use case di web scraping e le use case di SERP tracking per scenari legittimi. Per i piani ProxyHat e le posizioni disponibili, consulta le pagine dedicate.
Confronto: tipi di proxy per Turnstile
| Tipo proxy | Trust score IP | Sticky session | Costo | Idoneo per cf_clearance |
|---|---|---|---|---|
| Datacenter | Basso (ASN noto) | Sì | $0.5-2/GB | Possibile ma sfidato spesso |
| Residenziale | Alto (ISP reale) | Sì con -session- | $3-8/GB | Sì — raccomandato |
| Mobile | Altissimo (operatore) | Limitato | $5-15/GB | Sì — premium |
| Rotating puro | Varia | No | $1-5/GB | No — IP cambia ogni req |
Key Takeaways
- Turnstile è una pipeline multi-segnale: JA4 + HTTP/2 SETTINGS + fingerprint browser + reputazione IP. Superarne uno non basta.
- cf_clearance è IP-pinned e UA-pinned: cambia uno dei due e il cookie è invalidato. Usa sessioni proxy sticky.
- Il browser reale batte la simulazione: Playwright/Puppeteer con un profilo Chrome autentico produce tutti i segnali corretti per costruzione.
- I proxy residenziali sono non negoziabili per cf_clearance: trust score più alto, challenge invisibile, riutilizzo del cookie.
- Rate limiting è critico: anche con tutto corretto, 1000 req/sec dallo stesso IP triggera un challenge interattivo.
- Legittimità prima della tecnica: automazione autorizzata e dati pubblici, mai credential abuse.
FAQ
Cosa sono gli internals di Cloudflare Turnstile?
Gli internals di Cloudflare Turnstile includono il JavaScript di managed-challenge che esegue proof-of-work, probe delle API del browser (navigator, canvas, WebGL, audio), e la raccolta di segnali TLS/HTTP/2. Il risultato è un trust score che determina se il client passa invisibile, riceve un challenge o viene bloccato. Il cookie cf_clearance emesso al superamento è legato a IP e User-Agent.
Perché gli internals di Turnstile importano per chi usa proxy?
Il cookie cf_clearance è IP-pinned: se l'IP cambia tra l'ottenimento del cookie e le richieste successive, il token viene rifiutato. Questo rende i proxy rotating inutilizzabili per Turnstile. I proxy residenziali con sessioni sticky (stesso IP per tutta la durata) sono essenziali per ottenere e riutilizzare cf_clearance in pipeline di automazione legittima.
Quale tipo di proxy funziona meglio con Cloudflare Turnstile?
I proxy residenziali con sessioni sticky sono la scelta ottimale. Offrono IP da ISP reali (trust score alto), permettono di mantenere lo stesso IP per tutta la sessione (necessario per cf_clearance), e riducono la probabilità di challenge interattivi. I proxy datacenter vengono sfidati più spesso; i mobile sono premium ma più costosi. I rotating puri non funzionano perché cambiano IP ad ogni richiesta.
Come evitare i blocchi implementando Turnstile bypass?
Usa un browser reale (Playwright headful) con proxy residenziali sticky, mantieni User-Agent costante, rate-limita le richieste (max 5-10 req/sec per IP), e ri-ottieni cf_clearance quando scade (dopo ~30 min). Non usare librerie HTTP pure con UA spoofato: il JA4 non corrisponderà e verrai sfidato. Combina fingerprint coerenti, IP residenziale stabile e pattern di traffico umano.
cf_clearance può essere condiviso tra IP diversi?
No. cf_clearance è crittograficamente legato all'IP e allo User-Agent usati durante il challenge. Se uno dei due cambia, il cookie viene rifiutato. Questo è il motivo per cui le sessioni sticky di ProxyHat (flag -session-) sono critiche: mantengono lo stesso IP di uscita per tutta la durata della sessione, permettendo di riutilizzare cf_clearance per tutte le richieste fino alla scadenza.






