Sicurezza dei JSON Web Token: Vulnerabilità Comuni e Soluzioni
I JWT sono lo standard de facto per l'autenticazione API, ma la loro apparente semplicità nasconde vere insidie di sicurezza. JWT mal configurati hanno portato a bypass dell'autenticazione, escalation dei privilegi e violazioni dei dati. Questa guida copre le vulnerabilità più critiche e come prevenirle.
Riepilogo della Struttura JWT
Un JWT consiste di tre parti codificate in Base64URL separate da punti:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ.signature
- Header: Algoritmo e tipo di token
- Payload: Claims (dati utente, scadenza, ecc.)
- Firma: Verifica crittografica
Ispeziona la struttura JWT con il nostro JWT Encoder/Decoder.
Per una comprensione fondamentale della struttura JWT, consulta la nostra guida JWT Token Spiegati.
Vulnerabilità Critiche
1. Attacco di Confusione degli Algoritmi
La vulnerabilità JWT più pericolosa. Se un server accetta l'header alg dal token senza validazione, un attaccante può:
Attacco: Cambiare l'algoritmo da RS256 (asimmetrico) a HS256 (simmetrico) e firmare il token falsificato con la chiave pubblica del server:
// Token falsificato dall'attaccante
header: { "alg": "HS256", "typ": "JWT" }
payload: { "sub": "admin", "role": "superadmin" }
// Firmato con la chiave PUBBLICA del server come segreto HMAC
Se il server verifica i token HS256 usando la chiave pubblica come segreto, il token falsificato passa la verifica.
Soluzione: Specifica sempre l'algoritmo atteso esplicitamente:
// SBAGLIATO - accetta qualsiasi algoritmo specificato dal token
jwt.verify(token, key);
// CORRETTO - forza un algoritmo specifico
jwt.verify(token, key, { algorithms: ['RS256'] });
2. Attacco dell'Algoritmo None
Alcune librerie accettano "alg": "none" — un token senza firma:
// Token falsificato senza firma
header: { "alg": "none", "typ": "JWT" }
payload: { "sub": "admin", "role": "superadmin" }
signature: "" // vuota
Soluzione: Non permettere mai l'algoritmo none in produzione. Crea esplicitamente una whitelist degli algoritmi consentiti.
3. Segreti di Firma Deboli
I JWT basati su HMAC (HS256/HS384/HS512) sono forti solo quanto il segreto:
// TERRIBILE - può essere forzato in secondi
secret = "password123"
// DEBOLE - vulnerabile ad attacco dizionario
secret = "my-jwt-secret"
// FORTE - 256+ bit di casualità
secret = "a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0"
Soluzione: Usa almeno 256 bit di casualità crittografica per i segreti HMAC. Ancora meglio, usa chiavi asimmetriche (RS256, ES256) dove la chiave di firma non deve mai essere condivisa.
4. Scadenza Mancante
I token senza scadenza non scadono mai — un token rubato concede accesso permanente:
// SBAGLIATO - nessuna scadenza
{ "sub": "user123", "role": "admin" }
// CORRETTO - scadenza breve
{
"sub": "user123",
"role": "admin",
"exp": 1705312800,
"iat": 1705309200,
"nbf": 1705309200
}
Best practice: Gli access token scadono in 15-60 minuti. Usa i refresh token (memorizzati in modo sicuro) per sessioni lunghe.
5. Dati Sensibili nel Payload
I payload JWT sono codificati in Base64URL, non crittografati. Chiunque può decodificarli:
echo "eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ" | base64 -d
# {"sub":"123","role":"admin"}
Non includere mai: Password, chiavi API, numeri di carta di credito, dati personali (codice fiscale, cartelle cliniche) o qualsiasi segreto nei payload JWT.
6. Memorizzazione dei Token (XSS vs CSRF)
| Memorizzazione | Vulnerabile XSS | Vulnerabile CSRF |
|---|---|---|
| localStorage | Sì | No |
| Cookie (senza flag) | Sì | Sì |
| Cookie HttpOnly | No | Sì |
| Cookie HttpOnly + SameSite | No | No |
Raccomandato: Memorizza i JWT in cookie HttpOnly, Secure, SameSite=Strict. Questo previene l'accesso JavaScript (difesa XSS) e le richieste cross-site (difesa CSRF).
Set-Cookie: token=eyJ...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
Checklist di Sicurezza
- Specifica esplicitamente gli algoritmi — non accettare mai dall'header del token
- Rifiuta l'algoritmo
none— richiedi sempre una firma - Usa segreti forti — 256+ bit per HMAC, 2048+ bit per RSA
- Imposta scadenze brevi — 15-60 minuti per gli access token
- Valida tutti i claims —
exp,iss,aud,nbf - Memorizza in cookie HttpOnly — non in localStorage
- Ruota i segreti periodicamente — pianifica la rotazione delle chiavi
- Non memorizzare mai dati sensibili nel payload
- Usa chiavi asimmetriche per sistemi distribuiti (RS256 o ES256)
- Implementa la revoca dei token — blacklist o scadenza breve + refresh token
Firma Asimmetrica vs Simmetrica
| Aspetto | HS256 (Simmetrico) | RS256 (Asimmetrico) |
|---|---|---|
| Chiave | Segreto condiviso | Coppia chiave privata/pubblica |
| Chi può firmare | Chiunque con il segreto | Solo il detentore della chiave privata |
| Chi può verificare | Chiunque con il segreto | Chiunque con la chiave pubblica |
| Distribuzione chiave | Il segreto deve essere condiviso in modo sicuro | Solo la chiave pubblica viene condivisa |
| Prestazioni | Più veloce | Più lento |
| Ideale per | Servizio singolo | Microservizi, sistemi distribuiti |
Raccomandazione: Usa ES256 (ECDSA) per le nuove applicazioni — fornisce sicurezza asimmetrica con prestazioni vicine a HMAC.
Strategie di Revoca dei Token
I JWT sono stateless per design — non esiste un modo integrato per revocarli. Strategie:
- Scadenza breve: Se i token scadono in 15 minuti, la finestra di un token rubato è limitata
- Rotazione dei refresh token: Emetti un nuovo refresh token ad ogni utilizzo; se un refresh token viene usato due volte, revoca tutti i token
- Blacklist: Memorizza gli ID dei token revocati (claim jti) e controlla ad ogni richiesta
- Versionamento dei token: Includi un numero di versione nei claims; incrementa la versione dell'utente al logout
FAQ
Dovrei usare JWT o cookie di sessione per l'autenticazione?
I cookie di sessione sono più semplici e sicuri per le applicazioni web tradizionali — il server controlla il ciclo di vita della sessione e la revoca è istantanea. I JWT sono migliori per API stateless, microservizi e app mobile dove la memorizzazione delle sessioni lato server è impraticabile. Se scegli i JWT, implementa le misure di sicurezza di questa guida.
Qual è il tempo di scadenza JWT ideale?
Per gli access token: 15-60 minuti. Più breve è più sicuro ma richiede refresh più frequenti. Per i refresh token: 1-30 giorni, memorizzati in cookie HttpOnly. Per token monouso (verifica email, reset password): 1-24 ore.
Risorse Correlate
- JWT Encoder/Decoder — Ispeziona e decodifica JWT in sicurezza
- JWT Token Spiegati — Comprendi struttura e flusso JWT
- Entropia delle Password Spiegata — Robustezza dei segreti di firma JWT