Autenticazione JWT: sicurezza senza stato
Sessioni contro JWTS. Il dibattito è infinito. Quando utilizzare i token Web JSON, come archiviarli in modo sicuro (HttpOnly) e come gestire la rotazione.
Il dibattito tra Session e Token
Autenticazione sessione (classica):
- L’utente accede.
- Il server crea un ID sessione (
sess_123). Lo memorizza in memoria/Redis. - Il server invia l’ID al cookie del client.
- Il cliente invia il cookie.
- Il server cerca “sess_123” in Redis. Trova “L’utente è Bob”. Pro: revocabile (Elimina da Redis = Utente disconnesso). Contro: Statefull. Hai bisogno di Redis. Più difficile da scalare tra le regioni.
Autenticazione JWT (The Modern):
- L’utente accede.
- Il server crea un token Web JSON. Contiene
{ id: 1, nome: "Bob" }. Lo firma con una chiave segreta. - Il server invia JWT al client.
- Il cliente invia JWT.
- Il server verifica la firma. Trova “L’utente è Bob”. Pro: apolide. Non è richiesta alcuna ricerca nel database. “Il token è la sessione”. Contro: irrevocabile. In caso di furto, valido fino alla scadenza.
Perché Maison Code ne parla
Noi di Maison Code creiamo microservizi e app mobili. Le sessioni sono terribili per le app mobili (i cookie sono difficili). Le sessioni sono terribili per i microservizi (la condivisione di un’istanza Redis su 10 servizi è accoppiata). JWT è il passaporto universale. Il servizio A può verificare il token emesso da Auth Service semplicemente conoscendo la chiave pubblica. Implementiamo rigidi flussi JWT per abilitare le nostre architetture headless.
L’anatomia di un JWT
Tre parti, separate da punti. “Intestazione.Payload.Firma”.
- Intestazione: Algoritmo (
HS256). - Carico utile: dati (
sub: 123,exp: 17000000). - Firma:
Hash (intestazione + payload + segreto).
Critico: il payload è codificato Base64, NON crittografato.
Chiunque può leggerlo (atob(token)).
Regola: non inserire mai segreti nel JWT. Nessuna password. Nessuna carta di credito.
Solo ID utente e ruoli pubblici.
Dove conservarlo? (La Guerra Santa)
Opzione 1: archiviazione locale
- Facile (
localStorage.setItem('token', t)). - Vulnerabile a XSS. Se l’attaccante esegue JS, legge il token.
Opzione 2: cookie HttpOnly
- Sicuro. JS limita l’accesso.
- Vulnerabile alla CSRF.
- Richiede
SameSite=Strict.
Verdenza del codice Maison: Cookie HttpOnly. CSRF è più facile da mitigare (SameSite) rispetto a XSS. Per le app mobili, utilizza Archiviazione sicura (portachiavi).
Il modello di token di accesso/token di aggiornamento
Per risolvere il problema “irrevocabile”.
- Token di accesso: durata breve (5 minuti). Utilizzato per chiamare l’API.
- Token di aggiornamento: lunga durata (7 giorni). Archiviato in modo sicuro (HttpOnly/DB). Utilizzato solo per ottenere un nuovo token di accesso.
Flusso:
- Il cliente effettua una chiamata API con il token di accesso.
- Il server dice “401 scaduto”.
- Il client chiama “/refresh-token” con Refresh Token.
- Il server controlla il DB. “Questo token di aggiornamento è bloccato? No.”
- Il server emette un nuovo token di accesso. Sicurezza: se il token di accesso viene rubato, funziona per 5 minuti. Se banni l’utente, elimini il token di aggiornamento dal DB. Vengono bloccati in massimo 5 minuti.
Algoritmo: HS256 contro RS256
- HS256 (simmetrico): il server firma e verifica con lo stesso segreto. Veloce. Semplice per i monoliti.
- RS256 (Asimmetrico): Firma del servizio di autenticazione con chiave privata. Altri servizi verificano con chiave pubblica.
- Questo è fondamentale per i microservizi. Il “Product Service” può verificare l’utente senza conoscere il segreto del Auth Service.
Il punto di vista dello scettico
“Le sessioni sono più semplici.” Contropunto: Sì, per un monolite con un server. Prova a eseguire sessioni quando hai un frontend Next.js su Vercel Edge Network e un backend Go su AWS. La latenza del “Checking Redis” uccide le prestazioni di Edge. JWT consente di controllare l’autenticazione at the Edge (verifica la firma in 1 ms) senza un viaggio nel DB.
Domande frequenti
D: Posso invalidare manualmente un JWT? R: No. Questo è il punto. Puoi implementare una “lista nera” (memorizzare ID JWT non validi in Redis), ma poi hai reinventato Sessions. Utilizzare invece tempi di scadenza brevi.
D: Quanto può essere grande un JWT? A: Mantienilo piccolo. Viene inviato in ogni intestazione HTTP. Se ci inserisci 50 permessi, rallenti ogni richiesta.
10. Rotazione dei token (la catena di aggiornamento)
I token di aggiornamento standard hanno un difetto: se rubati, il ladro può accedervi per 7 giorni. Soluzione: Aggiorna rotazione token.
- Il cliente invia il token di aggiornamento A.
- Il server restituisce il token di accesso B E Nuovo token di aggiornamento C.
- Il server elimina il token di aggiornamento A. Se il ladro tenta di utilizzare nuovamente il “Vecchio token di aggiornamento A” -> Allarme di sicurezza. Il server rileva il riutilizzo di un token revocato. Invalida immediatamente l’intera “Famiglia Token” (A, C e tutti i discendenti). Il ladro viene bloccato immediatamente. All’utente reale viene chiesto di effettuare nuovamente l’accesso.
11. JWKS (set di chiavi Web JSON)
Come si ruotano le Chiavi di firma?
Non puoi riaggregare la chiave pubblica nelle app ogni settimana.
Soluzione: endpoint JWKS (/.well-known/jwks.json).
L’Auth Server pubblica le sue chiavi pubbliche su un URL.
Il Resource Server li recupera dinamicamente (e li memorizza nella cache).
Se sospetti una compromissione della chiave, ruoti la chiave sul server di autenticazione, aggiorni il JWKS e tutti raccolgono la nuova chiave in 5 minuti.
12. OAuth 2.1 e il futuro
JWT è solo il formato token. OAuth 2.0 è il flusso. Il settore sta passando a OAuth 2.1 (consolidamento delle migliori pratiche).
- Niente più flusso implicito (token di accesso nell’hash dell’URL).
- PKCE (Proof Key for Code Exchange) è obbligatorio. Ora implementiamo PKCE anche per le app Web lato server. Previene gli attacchi di tipo “Iniezione di codice di autorizzazione”.
13. Autenticazione da macchina a macchina (credenziali cliente)
Cosa succede se “Cron Job A” deve chiamare “API B”?
Non c’è nessun utente. Nessuna password.
Utilizziamo il Flusso delle credenziali del cliente.
POST /token { client_id, client_secret }.
Restituisce un JWT.
Questo standardizza Auth. Che si tratti di un Utente (sub: user_1) o di una Macchina (sub: service_billing), l’API convalida semplicemente la firma JWT.
L’uniformità è sicurezza.
14. Conclusione
JWT è la valuta del web moderno.
Come il denaro, deve essere coniato con attenzione (Firma), conservato in modo sicuro (Sicuro) e controllato per eventuali contraffazioni (Verifica).
Non lanciare la tua criptovaluta. Utilizza le librerie (jsonwebtoken, jose).
Autenticazione interrotta?
Se gli utenti vengono disconnessi in modo casuale o stai archiviando token in LocalStorage, Maison Code può proteggere il flusso di autenticazione.
Mal di testa con l’autenticazione?
Proteggiamo l’autenticazione senza stato utilizzando JWT (modello di accesso/aggiornamento) e cookie HttpOnly per proteggere le identità tra i microservizi. Assumi i nostri architetti.