Mr TOTO / blog
· Autenticazione · Sicurezza · API · 6 min di lettura

JSON Web Token e autenticazione stateless

Un’introduzione alla struttura e alle firme dei JWT e a come questi token possono ridurre lo stato di sessione condiviso tra più server.

Le tre sezioni codificate di un JSON Web Token
Un JWT combina header, payload e firma separati da punti.

Nota storica: questo articolo è stato pubblicato per la prima volta nel 2016. I JWT sono ancora molto utilizzati, ma un’implementazione sicura richiede anche una rigorosa validazione dei claim, scadenze brevi, una gestione sicura delle chiavi e una strategia chiara per la revoca. Un payload firmato è leggibile: non è cifrato.

Un JSON Web Token, o JWT, è uno standard compatto per trasportare claim tra due parti. Dopo aver autenticato un utente, un server può creare un token contenente un identificatore e altre informazioni limitate. Il client restituisce quel token nelle richieste successive, permettendo a qualsiasi server che ne riconosca la firma di verificarlo senza dipendere da una sessione locale.

Perché utilizzare un token?

Un login tradizionale crea spesso sul server una sessione contenente l’identificatore dell’utente. La situazione diventa più complessa quando il traffico viene distribuito tra diversi server applicativi. Se una sessione nasce sul server A e la richiesta successiva raggiunge il server B, lo stato deve essere replicato, memorizzato centralmente oppure mantenuto sullo stesso server tramite sticky routing.

Un token API opaco presenta un compromesso simile. Il server può memorizzarlo in un database e cercarlo a ogni richiesta, ma in questo modo crea uno stato condiviso e aggiunge un’altra interrogazione al flusso di autenticazione.

Un JWT adotta un approccio diverso. I claim necessari a identificare la sessione vengono inseriti nel token e protetti da una firma crittografica. Il client può leggere quei claim, ma modificarli invalida la firma. Un server può quindi verificare il token localmente, purché disponga della chiave corretta e convalidi tutti i claim richiesti.

Questo non elimina ogni accesso al database dell’applicazione. Significa soltanto che la verifica di base del token non richiede una ricerca. Regole di autorizzazione, stato dell’account, revoca e dati aggiornati possono comunque dipendere da informazioni conservate sul server.

Le tre parti di un JWT

Un token contiene tre sezioni codificate in Base64URL e separate da punti.

Header

Un header JWT che dichiara il tipo di token e l’algoritmo di firma

L’header è un piccolo oggetto JSON che descrive il tipo di token e l’algoritmo di firma. Una volta codificato, diventa la prima sezione del token.

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

Un payload JWT contenente claim di esempio

Il payload contiene claim relativi al soggetto e al token stesso. Lo standard definisce claim registrati come sub (soggetto), exp (scadenza), iss (emittente) e aud (destinatario), mentre le applicazioni possono aggiungere con attenzione claim propri.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Base64URL è una codifica, non una cifratura. Chiunque possieda il token può decodificare questa sezione, quindi non deve contenere segreti o informazioni personali non necessarie.

Firma

Un diagramma che mostra come viene calcolata la firma di un JWT

La firma permette al destinatario di rilevare modifiche e verificare chi ha emesso il token. Con un algoritmo HMAC come HS256, il server firma header e payload codificati usando un segreto condiviso. Con un algoritmo asimmetrico, l’emittente firma con una chiave privata e gli altri servizi verificano usando la corrispondente chiave pubblica.

Il server restituisce al client il token completo. A ogni richiesta protetta, il client lo invia nuovamente, di solito in un header Authorization: Bearer. Il server verifica la firma e poi controlla claim come scadenza, emittente, destinatario e soggetto prima di considerarlo attendibile.

È sicuro?

JWT è un formato, non un’architettura di autenticazione completa. La sua sicurezza dipende dalle scelte progettuali che lo accompagnano:

  • usare una libreria mantenuta e consentire esplicitamente soltanto gli algoritmi attesi;
  • mantenere le chiavi di firma robuste, private, ruotate e separate per ambiente;
  • convalidare exp, nbf, iss e aud quando applicabili;
  • usare HTTPS, perché un token valido può comunque essere rubato durante il transito o da un client non sicuro;
  • mantenere i token di breve durata e pianificare la revoca delle sessioni compromesse;
  • memorizzare i token considerando i rischi XSS e CSRF della specifica applicazione.

I JWT possono essere utili quando più servizi devono verificare la stessa identità senza condividere una sessione locale. Vanno scelti quando questa caratteristica serve davvero al sistema, non soltanto perché sembrano più moderni delle sessioni.

Riferimenti