JWT
2 strumenti
Fondamentali della sicurezza Web
La sicurezza Web è la pratica di proteggere le applicazioni Web e le API da accessi non autorizzati, violazioni dei dati e attacchi. Le applicazioni moderne usano autenticazione (verificare chi sei), autorizzazione (verificare cosa puoi fare) e crittografia per definire i confini di sicurezza.
I JSON Web Token (JWT) sono il meccanismo di autenticazione stateless dominante nello sviluppo Web moderno. Comprendere come funzionano i JWT — inclusa la loro struttura, gli algoritmi di firma e le vulnerabilità — è essenziale per costruire API e applicazioni sicure. Grazie alla loro natura compatta e autocontenuta, i JWT si sono affermati come standard de facto in OAuth2 e OpenID Connect.
JSON Web Tokens (JWT)
Un JWT è un modo compatto e sicuro per URL di rappresentare claim tra due parti. È composto da tre parti codificate in Base64url separate da punti. I JWT possono essere verificati senza interrogazioni al database perché la firma copre l'intero token: ciò li rende ideali per architetture distribuite e microservizi dove più servizi devono convalidare le identità in modo indipendente.
Le tre parti di un JWT
Contiene metadati sul token: l'algoritmo di firma (alg) e il tipo di token (typ). È sempre JSON codificato in Base64url. La scelta dell'algoritmo nell'intestazione influisce sulla sicurezza dell'intero token.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9{
"alg": "HS256",
"typ": "JWT"
}Contiene i claim: dichiarazioni sull'utente e metadati aggiuntivi. Anche questo è JSON codificato in Base64url. I dati del payload NON sono crittografati, solo firmati. Chiunque intercetti il token può decodificare e leggere il payload senza alcuna chiave.
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzIwMDAwMH0{
"sub": "user_123",
"role": "admin",
"exp": 1717200000
}Una firma crittografica sull'intestazione e il payload codificati. La verifica garantisce che il token non sia stato manomesso. La chiave segreta (HMAC) o la chiave privata (RSA/ECDSA) non è mai inclusa nel token e non deve mai essere distribuita a parti non fidate.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHMACSHA256( base64url(header) + "." + base64url(payload), secret )
Claim JWT standard
La specifica JWT definisce nomi di claim standard per garantire l'interoperabilità tra diverse librerie e servizi. Oltre ai claim standard, è possibile aggiungere claim personalizzati (private claims) per includere informazioni specifiche dell'applicazione, come i ruoli dell'utente o i permessi.
| Claim | Nome | Descrizione |
|---|---|---|
| iss | Issuer | Identifica il principal che ha emesso il token (es. URL del server di autenticazione) |
| sub | Subject | Identifica il principal che è il soggetto del token (es. ID utente) |
| aud | Audience | Identifica i destinatari per cui il token è destinato (es. URL della tua API) |
| exp | Expiration | Timestamp Unix dopo il quale il token non deve essere accettato |
| nbf | Not Before | Timestamp Unix prima del quale il token non deve essere accettato |
| iat | Issued At | Timestamp Unix in cui il token è stato emesso — usato per determinarne l'età |
| jti | JWT ID | Identificatore univoco del token, usato per prevenire attacchi di replay |
Algoritmi di firma
L'algoritmo di firma è dichiarato nell'intestazione JWT. La scelta corretta è fondamentale per la sicurezza. Gli algoritmi asimmetrici come RS256 ed ES256 sono generalmente preferiti in produzione perché separano la capacità di emettere token da quella di verificarli: il server di autenticazione mantiene la chiave privata, mentre i servizi che consumano i token verificano usando solo la chiave pubblica.
HS256 / HS384 / HS512Simmetrico (HMAC)Usa una chiave segreta condivisa per la firma e la verifica. Semplice da implementare, ma richiede che tutti i verificatori conoscano il segreto.
RS256 / RS384 / RS512Asimmetrico (RSA)Usa una chiave privata per firmare e una pubblica per verificare. La chiave privata non lascia mai il server di autenticazione. Le chiavi pubbliche possono essere distribuite liberamente tramite un endpoint JWKS.
ES256 / ES384 / ES512Asimmetrico (ECDSA)Come RSA ma con chiavi più piccole e firma più veloce. Offre sicurezza equivalente con prestazioni migliori.
"alg": "none"Non firmato — PERICOLOSONessuna firma. Un token con alg:none non ha garanzie di integrità e può essere falsificato da chiunque.
Flussi di autenticazione
- 1.L'utente invia nome utente e password all'endpoint di login
- 2.Il server valida le credenziali contro il database utenti
- 3.Il server firma un JWT con i claim dell'utente e la scadenza
- 4.Il client memorizza il JWT (localStorage, cookie o memoria)
- 5.Il client invia il JWT nell'intestazione Authorization: Bearer per le richieste successive
- 1.Il client reindirizza l'utente al server di autorizzazione con la sfida del codice
- 2.L'utente si autentica e autorizza l'applicazione client
- 3.Il server di autenticazione reindirizza con un codice di autorizzazione monouso
- 4.Il client scambia codice + verificatore per token di accesso e aggiornamento
- 5.Il client usa il token di accesso per le chiamate API; il token di aggiornamento per il rinnovo
Vulnerabilità JWT comuni
I JWT sono sicuri quando implementati correttamente. Questi sono gli errori di implementazione più comuni che portano a vulnerabilità di sicurezza. La maggior parte degli attacchi noti non sfrutta debolezze crittografiche, ma errori nella logica di validazione lato server: per questo è fondamentale usare librerie aggiornate e configurarle esplicitamente.
Alcune librerie accettano token con alg:none (nessuna firma). Un attaccante può modificare il payload e impostare alg su none per falsificare qualsiasi JWT. Specifica e valida sempre esplicitamente l'algoritmo consentito.
Se una libreria deve verificare RS256 ma accetta HS256, un attaccante può firmare un token usando la chiave pubblica come segreto HMAC. La libreria lo verifica con successo. Fissa sempre l'algoritmo atteso nella configurazione della libreria.
Un JWT senza claim exp, o codice che non controlla exp, permette l'uso indefinito dei token anche dopo che un utente si è disconnesso o è stato disabilitato. Imposta sempre brevi tempi di scadenza e verifica il claim exp ad ogni richiesta.
I payload JWT sono codificati in Base64, non crittografati. Chiunque intercetti un JWT può decodificare e leggere il payload. Non memorizzare mai password, numeri di carta di credito o altri segreti nei claim JWT. Se è necessario trasmettere dati sensibili nel token, utilizzare JWE (JSON Web Encryption).
I JWT firmati con HMAC con segreti brevi o prevedibili possono essere violati offline con forza bruta. Un attaccante che ottiene un JWT può provare miliardi di chiavi al secondo. Usa segreti casuali crittograficamente sicuri di almeno 256 bit.
Accettare JWT senza verificare la firma si fida completamente del payload. Questo è un bug critico che consente a qualsiasi utente di creare claim arbitrari. Verifica sempre la firma prima di fidarti di qualsiasi claim.
Domande frequenti
I JWT standard (JWS — JSON Web Signature) sono firmati ma NON crittografati. Il payload è codificato in Base64url, facilmente reversibile. Chiunque ottenga un JWT può leggerne il contenuto. JWE (JSON Web Encryption) fornisce crittografia reale, ma è molto meno comune e aggiunge complessità operativa.
I token di accesso dovrebbero essere di breve durata: da 5 a 60 minuti è tipico. I token di lunga durata sono pericolosi perché non possono essere revocati senza una lista di blocco. Usa token di aggiornamento (a lunga durata, memorizzati in modo sicuro) per ottenere nuovi token di accesso. In contesti ad alta sicurezza, come operazioni finanziarie o accesso a dati sensibili, considera token di accesso con validità di soli 5-15 minuti.
I cookie HttpOnly sono l'opzione più sicura — inaccessibili a JavaScript, prevenendo il furto tramite XSS. localStorage è vulnerabile agli attacchi XSS ma evita il CSRF. La memoria (variabile JavaScript) è la più sicura ma non sopravvive al refresh della pagina. Non esiste un'opzione perfetta: la scelta dipende dal modello di minaccia dell'applicazione e dall'uso combinato di misure di mitigazione come Content Security Policy.
Non senza stato lato server. La natura stateless dei JWT significa che il server non può invalidarli. Soluzioni: brevi tempi di scadenza, una lista di blocco dei token (Redis), token di aggiornamento rotanti, oppure passare a token di sessione opachi per operazioni sensibili. Una lista di blocco basata sul claim jti (JWT ID) consente la revoca precisa di singoli token senza invalidare l'intera sessione utente.
I cookie di sessione memorizzano un ID di sessione casuale; il server cerca i dati di sessione nel database o nella cache. I JWT sono autonomi — il server valida la firma senza query al database. I JWT scalano meglio su più server ma non possono essere revocati senza infrastrutture aggiuntive. I cookie di sessione sono più semplici da revocare ma richiedono storage condiviso in ambienti distribuiti.
Il minimo: sub (ID utente), exp (scadenza) e iat (emesso il). Aggiungi iss (issuer) per configurazioni multi-servizio e aud (audience) per limitare l'uso del token a specifici servizi. Mantieni i payload piccoli — i JWT vengono inviati con ogni richiesta. Non includere dati sensibili né oggetti profilo di grandi dimensioni.
RS256 (asimmetrico) è migliore per la maggior parte dei sistemi di produzione perché solo il server di autenticazione ha bisogno della chiave privata. Più servizi possono verificare i token usando la chiave pubblica senza condividere un segreto. HS256 è più semplice ma richiede che tutti i verificatori conoscano il segreto condiviso, aumentando la superficie di attacco in architetture con molti servizi.
PKCE (Proof Key for Code Exchange) è un'estensione del flusso di codice di autorizzazione OAuth2 che previene gli attacchi di intercettazione del codice. È obbligatorio per i client pubblici (SPA, app mobile) che non possono memorizzare in modo sicuro un client secret. Funziona generando una coppia di valori casuali — code verifier e code challenge — che legano la richiesta di autorizzazione allo scambio del token, rendendo inutilizzabile un codice intercettato.