Torna al blog

Come superare il TLS/JA4-fingerprinting nel 2026: curl_cffi e impersonificazione del browser in pratica

Abbiamo acquistato proxy residenziali, ma il sito continua a restituire 403 alla prima richiesta? Ti identificano tramite il handshake TLS già prima degli header HTTP. Analizziamo il fingerprinting JA3/JA4 e come aggirarlo in cinque minuti tramite curl_cffi e impersonificazione del browser — con codice, verifica del fingerprint e scelta del proxy.

📅21 luglio 2026
Come superare il TLS/JA4-fingerprinting nel 2026: curl_cffi e impersonificazione del browser in pratica
```html

Hai acquistato proxy residenziali, hai impostato un nuovo User-Agent Chrome, eppure il sito restituisce comunque un 403 alla prima richiesta. Ti suona familiare? Il problema non è nell'IP e nemmeno negli header. Ti hanno individuato ancora prima che il server leggesse un solo header HTTP — tramite il handshake TLS. Nel 2026 questo è il vettore di rilevamento numero 1, e una normale requests lo fallisce automaticamente. Analizziamo come funziona e come risolverlo con poche righe di codice tramite curl_cffi.

Cosa succede: il tuo TLS handshake ti tradisce

Quando un client stabilisce una connessione HTTPS, invia per primo il pacchetto ClientHello — ancora prima di qualsiasi HTTP. In esso sono elencati: la versione TLS, l'elenco dei cipher supportati (cipher suites), le estensioni TLS (SNI, ALPN, supported_groups), le curve ellittiche e i formati dei punti. L'ordine e il contenuto di questi campi variano tra i diversi client e da essi è possibile identificare il client prima ancora che pronunci una parola.

Da questi campi si calcola l'impronta. JA3 (standard del 2017) prende una stringa del tipo TLSVersion,Ciphers,Extensions,EllipticCurves,ECPointFormats e la hash con MD5, ottenendo una firma di 32 caratteri. Il problema di JA3 è che da gennaio 2023 Chrome randomizza l'ordine delle estensioni — 16 estensioni danno 16! (oltre 20 trilioni) di varianti, e lo stesso browser restituisce diversi JA3.

Per questo l'industria è passata a JA4 (FoxIO, implementazione di massa 2024–2025). JA4 ordina i codici delle estensioni in base al valore esadecimale prima dell'hashing — la randomizzazione di Chrome non lo rompe più. L'hash è un SHA-256 troncato, il formato è leggibile dall'uomo e suddiviso in tre parti (a_b_c), include ALPN e supporto per QUIC/HTTP3. Esempio: Chrome 124 dà t13d1516h2 (15 cifrari, 16 estensioni, ALPN h2), mentre Python puro requests restituisce t13d1715h2. Per un anti-bot, la seconda firma è un chiaro indicatore "questo è uno script".

Perché nel 2026 senza questo non si va da nessuna parte

Il rilevamento JA4 è integrato in tutti i principali fornitori: Cloudflare confronta l'impronta con le allowlist, Akamai aggiunge un hash separato per i frame HTTP/2 SETTINGS, DataDome confronta con il database dei bot noti. La logica è semplice e letale: se invii User-Agent: Chrome 131, ma l'impronta TLS grida "urllib3/OpenSSL" — c'è un disallineamento, e vieni bloccato immediatamente. Nessun proxy ti salva: un perfetto IP residenziale con impronta Python requests perde comunque.

Proprio per questo, la combinazione "proxy + falsificazione dell'impronta" è diventata nel 2026 una pratica di base per lo scraping, non un'opzione per esperti.

Soluzione: curl_cffi in 5 minuti

curl_cffi è un wrapper Python sopra curl-impersonate (curl modificato, compilato con BoringSSL da Chrome o NSS da Firefox invece di OpenSSL). Riproduce un autentico handshake del browser e ha un'API quasi identica alla consueta requests.

Passo 1. Installazione. I binari curl-impersonate per Windows/macOS/Linux vengono scaricati automaticamente:

pip install curl-cffi

Passo 2. Richiesta di base. Cambia l'import e aggiungi un parametro:

from curl_cffi import requests

resp = requests.get("https://target.com/", impersonate="chrome")
print(resp.status_code)
print(resp.http_version)  # HTTP/2 — come un vero browser

Una riga impersonate="chrome" falsifica immediatamente quattro livelli: impronta TLS (JA3/JA4), versione HTTP (HTTP/2 invece di HTTP/1.1), ordine degli header e negoziazioni ALPN.

Passo 3. Usa sempre l'alias generico, non fissare la versione. Scrivi impersonate="chrome" (o "safari", "safari_ios") — l'alias viene risolto automaticamente nel profilo più recente. Un impersonate="chrome124" hardcoded diventerà obsoleto: Chrome si aggiorna ogni ~4 settimane, e un vecchio profilo diventerà un'anomalia. I target affidabili sono Chrome, Edge e Safari/iOS (profili da chrome99 a chrome131, safari15–18).

Passo 4. Proxy e sessioni. Per uno scraping reale, mantieni lo stato in una sessione e collega i proxy. È obbligatorio avere un IP residenziale o mobile — i data center vengono individuati separatamente dall'ASN rispetto al TLS:

from curl_cffi import requests

session = requests.Session(impersonate="chrome")

headers = {
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.google.com/",
}
proxies = {
    "http": "http://user:pass@proxy-host:port",
    "https": "http://user:pass@proxy-host:port",
}

resp = session.get("https://target.com", headers=headers, proxies=proxies)

Passo 5. Asincronia per il volume. A differenza di requests, curl_cffi ha nativamente async e HTTP/2:

import asyncio
from curl_cffi.requests import AsyncSession

async def fetch(session, url):
    r = await session.get(url, impersonate="chrome")
    return r.status_code

async def main(urls):
    async with AsyncSession() as session:
        return await asyncio.gather(*[fetch(session, u) for u in urls])

asyncio.run(main(["https://target.com"] * 20))

Controlla la tua impronta — non indovinare

Prima di inviare traffico reale, assicurati che la falsificazione funzioni realmente. Invia una richiesta a verificatori pubblici e confronta JA4 con quello di un browser di riferimento:

  • tls.peet.ws — restituisce JA3, JA4, impronta Akamai e frame HTTP/2 in JSON. Richiedilo tramite curl_cffi e tramite un vero Chrome, confronta gli hash.
  • ja4db.com — database di JA4 noti, aiuta a capire a chi assomigli.
  • browserleaks.com/tls e lo strumento JA3/JA4 di Scrapfly — analisi dettagliata dei campi.

In fase di staging, è comodo inserire mitmproxy tra lo scraper e il target e monitorare il reale hash JA4 di ogni richiesta.

Diagnosi: continui a ricevere 403/429

Se l'impronta è corretta, ma i blocchi persistono — segui la checklist dal più comune al più raro:

  1. IP da data center. Motivo n. 1. Passa a proxy residenziali o mobile — perché un'impronta da sola non basta, è spiegato dettagliatamente nel materiale su rilevamento dei proxy residenziali tramite IP Intelligence.
  2. Profilo scaduto. pip install -U curl-cffi e alias generico "chrome".
  3. Rate troppo alto. Aggiungi pause casuali di 1–3 secondi tra le richieste.
  4. Header nudi. Assicurati di inviare Accept-Language, Accept-Encoding, Referer — la loro assenza è anch'essa un'anomalia.
  5. Disallineamento tra sessione e IP. Regola: una sessione — un IP per tutta la sua durata.
  6. Stato 200 ≠ successo. Controlla il corpo della risposta: sotto il codice 200 potrebbe esserci una pagina con CAPTCHA.

Dove curl_cffi si scontra con un muro

curl_cffi chiude il layer di rete — e basta. Non esegue JavaScript. Pertanto, contro le sfide JS è impotente: Cloudflare Turnstile, pagina "Controllo del tuo browser…" (IUAM), cookie cf_clearance impostato dallo script dopo il controllo — tutto ciò richiede un vero ambiente browser. Perché nel 2026 i solver di CAPTCHA hanno quasi smesso di funzionare contro tali sistemi preventivi, lo abbiamo analizzato in un'analisi separata sull'aggiramento dei CAPTCHA.

Cosa fare quando ti scontri con un muro JS:

  • Ibrido. Playwright o Nodriver esegue la sfida e ottiene cf_clearance, poi il cookie viene passato a un veloce curl_cffi per la maggior parte delle richieste — in questo modo paghi per un browser pesante una sola volta.
  • Servizi di solver (CapSolver, 2Captcha) per l'emissione automatica di token.
  • API di scraping gestito, se non vuoi mantenere l'infrastruttura.

E ricorda la sicurezza dei thread: ogni thread — la sua sessione. Fissa la versione curl-cffi in requirements.txt e rivedi i profili ogni 6–12 settimane, quando i browser si aggiornano.

Alternative a curl_cffi

  • tls-client — wrapper sopra la libreria Go basata su uTLS, con profili (chrome_124, safari_ios_17) e flag random_tls_extension_order=True. Flessibile e con una fine regolazione dell'impronta.
  • primp — client in Rust, consente di impostare indipendentemente impersonate_os e offre una maggiore larghezza di banda; svantaggio — l'API non coincide completamente con requests e la libreria è più giovane.

Quale proxy serve e perché

La falsificazione dell'impronta e i proxy risolvono due metà di un unico problema: curl_cffi chiude la questione "come appare la connessione", i proxy — "da dove proviene". L'anti-bot verifica entrambi i segnali in modo indipendente, quindi un perfetto JA4 con un ASN di data center nero è inutile. Per obiettivi protetti (marketplace, social media, aggregatori di viaggi) utilizza proxy residenziali o mobile: hanno una provenienza operatore pulita, e i mobile si nascondono anche dietro l'effetto CGNAT "effetto folla". Lascia i data center per obiettivi non sensibili e alto volume.

Conclusione

Nel 2026, lo scraping è un gioco di identità, non solo di IP. Una semplice requests appare come uno script a livello di handshake TLS e perde ancora prima del primo header. Sostituire l'importazione con curl_cffi e impersonate="chrome" elimina questo fallimento in cinque minuti, ma funziona solo in combinazione con un IP residenziale o mobile pulito e con la comprensione del confine: layer di rete — sì, sfide JavaScript — no. Costruisci stack in modo onesto: impronta corretta, proxy corretto, ibrido con browser dove c'è un muro JS — e il 403 alla prima richiesta rimarrà nel passato.

```