Fingerprinting HTTP/2 spiegato: come i server rilevano l'automazione nel 2026

Il fingerprinting HTTP/2 ispeziona frame SETTINGS, ordine pseudo-header e WINDOW_UPDATE per identificare bot. Guida pratica con curl_cffi, proxy residenziali e ProxyHat per fingerprint coerenti.

HTTP/2 Fingerprinting Explained: How Protocol Signals Expose Automation in 2026

Se gestisci infrastrutture di scraping o automazione browserless, hai probabilmente notato che i sistemi anti-bot più avanzati — Akamai Bot Manager, Cloudflare, DataDome — non si limitano più a controllare il tuo indirizzo IP o il tuo fingerprint TLS. Dal 2024, questi sistemi ispezionano il fingerprinting HTTP/2 spiegato a livello di frame: i parametri SETTINGS, l'ordine degli pseudo-header, i valori WINDOW_UPDATE e la priorità degli stream. Un client Python come httpx che dichiara Chrome 148 tramite JA4 ma invia HEADER_TABLE_SIZE 4096 viene flaggato con il massimo bot score prima ancora che l'HTML venga scaricato.

Cos'è il fingerprinting HTTP/2 spiegato

Il fingerprinting HTTP/2 è la tecnica con cui un server identifica il client che si connette analizzando i frame di controllo e di intestazione del protocollo HTTP/2, prima ancora che il contenuto della risposta venga processato. A differenza del fingerprinting TLS (JA3/JA4), che opera al livello di trasporto e viene completato durante l'handshake, il fingerprinting HTTP/2 avviene dopo l'handshake TLS, nei primi millisecondi della connessione HTTP/2 stessa.

Il protocollo HTTP/2, definito nella RFC 9113, prevede che il client invii un frame SETTINGS immediatamente dopo il preface magico (PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n). Questo frame contiene parametri di configurazione che ogni implementazione imposta in modo diverso. Poiché la specifica lascia ai client ampia libertà sui valori predefiniti, ogni browser e ogni libreria HTTP produce un SETTINGS frame con valori distinti — un vero e proprio impronta digitale.

I sistemi anti-bot moderni confrontano questa impronta con un database di fingerprint noti. Se il tuo client dichiara di essere Chrome tramite l'User-Agent e il fingerprint TLS, ma il frame SETTINGS corrisponde a quello della libreria h2 di Python, il server assegna un punteggio di bot elevato. La discrepanza è immediatamente rilevabile perché i browser non inviano mai HEADER_TABLE_SIZE 4096 — il valore predefinito di nghttp2/httpx.

Il frame SETTINGS e i parametri fingerprintati

Il frame SETTINGS è il vettore principale del fingerprinting HTTP/2. I parametri che vengono ispezionati sono cinque:

  • HEADER_TABLE_SIZE (0x1): la dimensione della tabella di compressione HPACK. Chrome imposta 65536 byte, Firefox 65536, mentre la libreria h2 di Python usa 4096 byte come predefinito — un valore che nessun browser mainstream utilizza.
  • ENABLE_PUSH (0x2): indica se il client accetta server push. Chrome imposta 0 (disabilitato) dalla versione 73+, Firefox 0, Safari 1. Un client che non invia questo parametro o lo imposta a 1 è sospetto.
  • MAX_CONCURRENT_STREAMS (0x3): il numero massimo di stream concorrenti. Chrome invia 1000, Firefox 1000. La libreria h2 non invia questo parametro, lasciando il valore al default del server (di solito illimitato).
  • INITIAL_WINDOW_SIZE (0x4): la dimensione iniziale della finestra di controllo di flusso. Chrome imposta 6291456 byte (6 MB), Firefox 131072 byte (128 KB). Il valore predefinito di h2 è 65535 byte — diverso da entrambi i browser.
  • MAX_HEADER_LIST_SIZE (0x6): la dimensione massima della lista header. Chrome invia 262144 byte (256 KB). h2 non invia questo parametro.

Oltre al frame SETTINGS, vengono fingerprintati altri due segnali:

  • WINDOW_UPDATE: dopo il frame SETTINGS, il client invia un frame WINDOW_UPDATE a livello connessione per aumentare la finestra di controllo di flusso. Chrome invia un incremento di 15663105 byte, portando la finestra totale a 15728640 byte (15 MB). Questo valore è specifico di Chrome e non viene replicato da alcuna libreria HTTP standard.
  • Stream priority: Chrome utilizza un albero di priorità basato su dipendenze e pesi. Nei frame HEADERS o PRIORITY, invia informazioni sulla dipendenza dello stream (stream ID 0 per la root, pesi specifici). La libreria h2 non replica questa struttura.

Ordine degli pseudo-header

Il terzo segnale critico è l'ordine degli pseudo-header HTTP/2. La RFC 9113 richiede che gli pseudo-header (:method, :path, :scheme, :authority) precedano gli header regolari, ma non specifica l'ordine tra loro. Ogni browser usa un ordine diverso:

  • Chrome: :method, :authority, :scheme, :pathm,a,s,p
  • Firefox: :method, :path, :scheme, :authoritym,p,s,a
  • Safari: :method, :scheme, :path, :authoritym,s,p,a

La libreria h2 di Python invia gli pseudo-header nell'ordine m,s,p,a — che non corrisponde a nessun browser mainstream. Questo è un segnale inequivocabile di automazione.

L'impronta Akamai h2 e JA4H

Akamai è stato pioniere nella normalizzazione del fingerprinting HTTP/2. Il formato Akamai h2 fingerprint compatta tutti i segnali del protocollo in una singola stringa con la struttura:

SETTINGS_KEY:VALUE,SETTINGS_KEY:VALUE,...|WINDOW_UPDATE|PRIORITY|PSEUDO_HEADER_ORDER

Per esempio, il fingerprint HTTP/2 di Chrome 148 su Windows appare così:

1:65536,2:0,3:1000,4:6291456,6:262144|15663105|0|m,a,s,p

Dove 1:65536 è HEADER_TABLE_SIZE:65536, 2:0 è ENABLE_PUSH:0, e così via. Il valore 15663105 dopo il primo pipe è l'incremento del WINDOW_UPDATE a livello connessione. Lo 0 dopo il secondo pipe indica l'assenza di un albero di priorità complesso (semplificato). Infine, m,a,s,p è l'ordine degli pseudo-header.

Il fingerprint di httpx con la libreria h2 appare invece:

1:4096,4:65535|0|0|m,s,p,a

La differenza è drammatica: valori diversi, parametri mancanti (nessun MAX_CONCURRENT_STREAMS, nessun MAX_HEADER_LIST_SIZE, nessun ENABLE_PUSH), e ordine pseudo-header errato. Un sistema anti-bot non ha bisogno di ML per classificare questo client come bot — basta un confronto esatto con il database dei fingerprint noti.

JA4H: il fingerprint HTTP standardizzato

JA4H è il componente HTTP della famiglia di fingerprint JA4 sviluppata da FoxIO. Mentre JA3/JA4 catturano il fingerprint TLS, JA4H cattura il fingerprint HTTP a livello applicazione. Il formato JA4H include:

  • Versione del protocollo HTTP (HTTP/1.1 vs HTTP/2 vs HTTP/3)
  • Numero di header e loro nomi (ordinati)
  • Lingua accettata (Accept-Language primary value)
  • Presenza di cookie e referer

Un esempio di JA4H per Chrome 148:

ge11nn20enus_acch..._c001_r001

Dove ge indica HTTP/2 su TLS, 11 è il numero di header, nn indica nessun Accept-Language secondario, 20 e enus codificano la lingua, e le sezioni dopo l'underscore elencano gli header ordinati, la presenza di cookie e referer.

JA4H e l'Akamai h2 fingerprint sono complementari: JA4H cattura gli header HTTP, mentre l'Akamai fingerprint cattura i frame del protocollo HTTP/2. Un sistema anti-bot moderno li utilizza entrambi.

Perché JA4 e HTTP/2 devono concordare

Il fingerprint TLS (JA4) e il fingerprint HTTP/2 devono essere coerenti. Se il tuo JA4 corrisponde a Chrome 148 su Windows — con le estensioni SNI, ALPN h2, le curve X25519 e l'ordine dei cipher di Chrome — ma il frame HTTP/2 SETTINGS contiene HEADER_TABLE_SIZE 4096, il server rileva una contraddizione immediata.

Questo accade perché i browser producono sia il fingerprint TLS che quello HTTP/2 dalla stessa implementazione (BoringSSL + nghttp2 per Chrome, NSS + neqo per Firefox). È praticamente impossibile che un JA4 Chrome si accompagni a un SETTINGS frame non-Chrome. I sistemi anti-bot trattano questa incongruenza come prova definitiva di spoofing.

La logica di scoring è semplice:

  1. Il server estrae il JA4 dal ClientHello TLS.
  2. Il server estrae l'h2 fingerprint dai frame HTTP/2.
  3. Il server verifica che la coppia (JA4, h2_fingerprint) sia presente nel database delle combinazioni note.
  4. Se la coppia non esiste — per esempio JA4 Chrome con h2 fingerprint di httpx — il bot score viene impostato al massimo prima ancora che la richiesta HTTP venga processata.

Questo significa che non basta modificare l'User-Agent o usare una libreria TLS che imita Chrome. Devi replicare entrambi i livelli: TLS e HTTP/2.

Client Python e Node che perdono frame incoerenti

La maggior parte delle librerie HTTP di alto livello produce fingerprint HTTP/2 che non corrispondono a nessun browser. Ecco i casi più comuni:

d>Nessuno
Client HEADER_TABLE_SIZE MAX_CONCURRENT_STREAMS INITIAL_WINDOW_SIZE Pseudo-header order Match browser
Chrome 148 65536 1000 6291456 m,a,s,p Nativo
Firefox 130 65536 1000 131072 m,p,s,a Nativo
httpx (Python, h2) 4096 non inviato 65535 m,s,p,a
requests (Python) N/A (HTTP/1.1) N/A N/A N/A Nessuno
Node http2 (nghttp2) 4096 non inviato 65535 m,s,p,a Nessuno
got (Node.js) 4096 non inviato 65535 m,s,p,a Nessuno
curl_cffi (impersonate=chrome) 65536 1000 6291456 m,a,s,p Chrome

Il pattern è chiaro: httpx, il modulo http2 di Node.js e got utilizzano tutti nghttp2 o la libreria h2 con i valori predefiniti, che non corrispondono a nessun browser. Il HEADER_TABLE_SIZE 4096 è il segnale più evidente — nessun browser mainstream lo usa.

curl_cffi si distingue perché utilizza la libreria curl-impersonate, che compila curl con BoringSSL e configura nghttp2 per replicare esattamente i valori SETTINGS dei browser specifici. Quando usi impersonate="chrome", curl_cffi produce un JA4 e un h2 fingerprint che corrispondono a Chrome.

Perché i proxy residenziali sono ancora necessari

Anche con un fingerprint HTTP/2 perfetto, lo spoofing del protocollo da solo non basta. I sistemi anti-bot moderni combinano fingerprinting a più livelli:

  • Reputazione IP: datacenter IP ranges (ASNs di AWS, DigitalOcean, Hetzner) ricevono un punteggio base elevato. Anche con un fingerprint HTTP/2 impeccabile, una richiesta da un IP datacenter viene penalizzata.
  • Geolocalizzazione: se il tuo JA4 dichiara Chrome su Windows ma l'IP è in un datacenter a Francoforte mentre l'Accept-Language è en-US, l'incongruenza geografica aumenta il bot score.
  • Comportamento storico: i sistemi anti-bot mantengono un punteggio cumulativo per ogni IP. Un IP datacenter che ha servito migliaia di richieste automatizzate ha già un punteggio elevato prima della tua connessione.

I proxy residenziali risolvono questo problema fornendo IP registrati come residenziali nei database ASN (MaxMind, IP2Location). Un IP residenziale ha un punteggio base basso perché l'ASN corrisponde a un ISP domestico (Comcast, AT&T, Vodafone). Combinato con un fingerprint HTTP/2 coerente, il risultato è una richiesta indistinguibile da quella di un utente reale.

ProxyHat offre proxy residenziali con geolocalizzazione a livello di paese e città, che puoi combinare con il fingerprint del browser per massimizzare la coerenza. Consulta la pagina prezzi per i piani disponibili e la pagina locations per la copertura geografica.

Implementazione pratica con curl_cffi e ProxyHat

L'approccio più robusto per produrre un fingerprint HTTP/2 coerente in Python è utilizzare curl_cffi con impersonate="chrome" e instradare il traffico attraverso proxy residenziali ProxyHat. Ecco un esempio completo:

Installazione

pip install curl_cffi

Richiesta base con fingerprint Chrome

from curl_cffi import requests

# ProxyHat residential proxy — geolocalizzato negli Stati Uniti
proxy_url = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

# Sessione con impersonazione Chrome 124
session = requests.Session(impersonate="chrome")
session.proxies = {"http": proxy_url, "https": proxy_url}

# Header coerenti con Chrome 124 su Windows
headers = {
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "accept-language": "en-US,en;q=0.9",
    "accept-encoding": "gzip, deflate, br, zstd",
    "sec-ch-ua": '\"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\", \"Not-A.Brand\";v=\"99\"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '\"Windows\"',
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "none",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
}

response = session.get("https://example.com", headers=headers)
print(f"Status: {response.status_code}")
print(f"JA4+h2 fingerprint coerente con Chrome 124")

Sessioni sticky per scraping multi-pagina

Per lo SERP tracking o lo scraping di pagine che richiedono sessioni persistenti, usa l'opzione session nel username ProxyHat per mantenere lo stesso IP di uscita:

from curl_cffi import requests

# Sessione sticky — stesso IP per tutta la durata della sessione
proxy_url = "http://user-country-US-session-stable01:PASSWORD@gate.proxyhat.com:8080"

session = requests.Session(impersonate="chrome")
session.proxies = {"http": proxy_url, "https": proxy_url}

# Prima richiesta — ottiene cookie di sessione
r1 = session.get("https://target-site.com/login", headers=headers)

# Seconda richiesta — stesso IP, stessi cookie, stesso fingerprint
r2 = session.get("https://target-site.com/dashboard", headers=headers)

print(f"Login: {r1.status_code}, Dashboard: {r2.status_code}")

Verifica del fingerprint con curl

Puoi verificare rapidamente il tuo fingerprint HTTP/2 usando curl da riga di comando attraverso ProxyHat:

# Richiesta HTTP/2 attraverso ProxyHat con fingerprint Chrome
curl --http2 \
  --proxy http://user-country-US:PASSWORD@gate.proxyhat.com:8080 \
  -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" \
  -H "accept-language: en-US,en;q=0.9" \
  -H "sec-ch-ua: \"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\"" \
  -H "sec-ch-ua-mobile: ?0" \
  -H "sec-ch-ua-platform: \"Windows\"" \
  -H "sec-fetch-dest: document" \
  -H "sec-fetch-mode: navigate" \
  -H "sec-fetch-site: none" \
  -H "upgrade-insecure-requests: 1" \
  -o /dev/null -w "%{http_version} %{http_code} %{time_total}s\n" \
  https://example.com

Il flag --http2 di curl utilizza nghttp2 con valori predefiniti che sono vicini a Chrome ma non identici. Per una corrispondenza esatta, usa curl-impersonate o curl_cffi con impersonate="chrome".

Rotazione IP per richieste ad alto volume

from curl_cffi import requests
import uuid

# Per ogni richiesta, genera un nuovo session ID → nuovo IP residenziale
def make_request(url, country="US"):
    session_id = uuid.uuid4().hex[:12]
    proxy_url = f"http://user-country-{country}-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
    
    session = requests.Session(impersonate="chrome")
    session.proxies = {"http": proxy_url, "https": proxy_url}
    
    return session.get(url, headers=headers, timeout=30)

# 100 richieste con IP diversi e fingerprint Chrome coerente
for i in range(100):
    r = make_request("https://target-site.com/page")
    print(f"Request {i+1}: {r.status_code}")

Per dettagli completi sulla configurazione dei proxy, consulta la documentazione ufficiale di ProxyHat.

HTTP/3 e QUIC: il prossimo livello di fingerprinting

HTTP/3, basato su QUIC, introduce nuove superfici di fingerprinting. Il frame SETTINGS di HTTP/3 include parametri aggiuntivi come QPACK_MAX_TABLE_CAPACITY e MAX_FIELD_SECTION_SIZE. Inoltre, il transport parameters di QUIC (esposti nel handshake TLS 1.3) contengono segnali come initial_max_data, initial_max_stream_data_bidi_local, e max_idle_timeout.

Chrome 148 invia transport parameters QUIC con valori specifici (per esempio, initial_max_stream_data_bidi_local: 6291456) che differiscono da quelli di Firefox e Safari. I sistemi anti-bot stanno iniziando a fingerprintare anche questi parametri, estendendo il modello del fingerprinting HTTP/2 a HTTP/3.

Per ora, la maggior parte del traffico di scraping rimane su HTTP/2 perché il supporto QUIC richiede UDP (spesso bloccato dai proxy HTTP). Tuttavia, se il target supporta HTTP/3 e il tuo client non lo gestisce, l'assenza di un upgrade HTTP/3 può essere essa stessa un segnale di automazione — i browser reali tentano sempre QUIC prima di fallback su HTTP/2.

Uso appropriato e considerazioni legali

Il fingerprinting HTTP/2 e l'uso di proxy residenziali per presentare un'identità coerente sono tecniche legittime in diversi contesti:

  • Ricerca di sicurezza autorizzata: penetration testing con scope scritto, bug bounty program, analisi di sistemi anti-bot per ricerca accademica.
  • Monitoraggio di prezzi e disponibilità: raccolta di dati pubblici da siti e-commerce che non vietano esplicitamente l'accesso automatizzato nei loro ToS.
  • Verifica di ad placement e SERP: controllo del posizionamento organico e a pagamento da diverse geolocalizzazioni.
  • QA e test di infrastrutture: simulazione di traffico realistico per testare la propria infrastruttura.

Tuttavia, queste tecniche non devono essere usate per:

  • Aggirare controlli di accesso o autenticazione non autorizzati (violazione del CFAA negli Stati Uniti).
  • Raccogliere dati personali in violazione del GDPR nell'UE o del CCPA in California.
  • Condurre frodi pubblicitarie, credential stuffing, o attacchi DDoS.
  • Violare i Terms of Service di un sito in modo che causi danni.

Consulta sempre il robots.txt e i ToS del target, e ottieni autorizzazione scritta quando possibile. Per approfondimenti sull'uso etico dei proxy, visita la pagina web scraping.

Errori comuni e casi limite

Errore 1: Modificare solo l'User-Agent

Il caso più comune: sviluppatori che impostano User-Agent: Mozilla/5.0... Chrome/124 su httpx e pensano di aver risolto. Il fingerprint HTTP/2 rimane quello di h2 con HEADER_TABLE_SIZE 4096. Il server rileva la discrepanza in meno di 200ms.

Errore 2: Usare TLS spoofing senza h2 spoofing

Alcuni sviluppatori usano librerie come tls-client o patchano l'ordine dei cipher TLS per ottenere un JA4 Chrome, ma continuano a usare httpx per le richieste HTTP/2. Il JA4 è coerente, ma il SETTINGS frame no. Il bot score rimane massimo.

Errore 3: Proxy datacenter con fingerprint perfetto

Un fingerprint HTTP/2 impeccabile da un IP AWS us-east-1 viene comunque flaggato. La reputazione IP ha un peso del 30-40% nel punteggio finale di molti sistemi anti-bot. Senza un proxy residenziale, il fingerprint è inutile.

Caso limite: HTTP/3 fallback

Se il target supporta HTTP/3 e il tuo client non lo gestisce, l'assenza di un upgrade HTTP/3 può essere essa stessa un segnale. I browser reali tentano QUIC prima di fallback su HTTP/2. Considera l'uso di browser headless (Playwright, Puppeteer) per target che richiedono HTTP/3.

Caso limite: Canvas fingerprint e segnali JavaScript

Il fingerprinting HTTP/2 è solo il primo livello. Se la pagina carica JavaScript, il server può verificare canvas fingerprint, WebGL renderer, font enumeration, e segnali comportamentali (mouse movement, typing cadence). Per i target più protetti, un browser headless con proxy residenziali è l'unica soluzione completa.

Key Takeaways

  • Il fingerprinting HTTP/2 ispeziona il frame SETTINGS (HEADER_TABLE_SIZE, INITIAL_WINDOW_SIZE, MAX_CONCURRENT_STREAMS), WINDOW_UPDATE, stream priority e l'ordine degli pseudo-header (m,a,s,p per Chrome).
  • L'Akamai h2 fingerprint compatta questi segnali in una stringa come 1:65536,2:0,3:1000,4:6291456,6:262144|15663105|0|m,a,s,p. JA4H estende il fingerprinting al livello HTTP applicativo.
  • Un client con JA4 Chrome ma SETTINGS frame di httpx (HEADER_TABLE_SIZE 4096) riceve il massimo bot score prima del caricamento dell'HTML.
  • curl_cffi con impersonate="chrome" produce sia il JA4 che l'h2 fingerprint di Chrome — è la soluzione più robusta in Python.
  • I proxy residenziali sono necessari perché la reputazione IP contribuisce per il 30-40% al bot score finale. Un fingerprint perfetto da un IP datacenter viene comunque flaggato.
  • Usa queste tecniche solo per ricerca autorizzata, monitoraggio legittimo e QA. Rispetta robots.txt, ToS, GDPR e CFAA.

Pronto a implementare fingerprint HTTP/2 coerenti con proxy residenziali? Esplora i piani ProxyHat e inizia a instradare il tuo traffico attraverso IP residenziali geolocalizzati con gate.proxyhat.com:8080.

Pronto per iniziare?

Accedi a oltre 50M di IP residenziali in oltre 148 paesi con filtraggio AI.

Vedi i prezziProxy residenziali
← Torna al Blog