JWT

Cos'è un JWT

JWT è un acronimo per Json-Web-Token ed è uno standard usato per trasferire informazioni tra varie applicazioni garantendone l'integrità. Il suo utilizzo principale è quello di rappresentare la sessione di un utente, sia in comuni applicazioni web monolitiche, che in applicazioni web costruite seguendo il parametro dei microservizi.

Un JWT è una stringa testuale composta da tre sezioni separate da .:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Le tre sezioni sono:

  • header: un JSON codificato in base64, che contiene informazioni sul JWT stesso come:
    • alg: algoritmo usato per firmare/autenticare il JWT stesso
  • payload (anche detto claims): un JSON codificato in base64 che contiene i dati che il creatore del token vuole condividere. Spesso contiene informazioni sull'utente come la sua mail, il suo ID, i suoi permessi, etc.
  • signature: è la firma che autentica il contenuto del token. Può essere prodotta in diversi modi in base al campo alg dell'header. Anche questa parte è codificata in base64 ma non è un json.

Autenticazione dei JWT

Come abbiamo visto la parte finale di un JWT è una firma. Per costruire questa firma si possono usare vari algoritmi, i più comuni sono:

  • HS256: l'header e il payload vengono autenticati tramite HMAC con SHA256, usando una stringa segreta condivisa. Chiunque conosca la stringa segreta può creare nuovi token e autenticare quelli esistenti, garantendone l'integrità.
  • RS256: l'header e il payload vengono firmati usando SHA256 e poi RSA. In questa configurazione per la firma si usa la chiave privata, che è conosciuta solo dal server che emette i token, e chiunque può autenticare il JWT controllando la firma con la chiave pubblica. Questo metodo è molto usato quando i JWT sono prodotti da un identity-provider esterno all'applicazione web, come ad esempio okta o keycloack.

Casi d'uso dei JWT

Sessione utente

L'utilizzo più comune dei JWT è quello di sostituire il cookie di sessione. Il backend genera un JWT con tutte le informazioni che vuole mettere nella sessione utente e poi lo invia al browser nella risposta (oppure lo imposta come cookie).

Stato condiviso tra microservizi

Nell'architettura a microservizi abbiamo varie applicazioni, spesso in vari linguaggi diversi che si parlano tra di loro. Dato che per prassi ogni applicazione ha il proprio database e si trova su un host diverso, è difficile condividere i dati di una sessione utente. Quindi si usa spesso condividere il segreto del JWT tra le varie applicazioni (o usare un microservizio centralizzato che li controlli) e aggiungere il token alle varie richieste attraverso i diversi microservizi.

Vulnerabilità comuni

Information leak

Bisogna fare attenzione a quali dati vengono inseriti all'interno del JWT. Il contenuto del JWT infatti non è criptato in alcun modo, ma solamente codificato, quindi inserendo informazioni riservate nel campo payload si potrebbero verificare degli information leak.

Algorithm none

Oltre agli algoritmi che abbiamo visto prima, lo standard definisce un altro algoritmo: none, che indica che il JWT non è autenticato, quindi ci si può affidare completamente e ciecamente al suo contenuto. Ovviamente mancando qualsiasi metodo per il controllo di autenticazione, un utente malevolo può costruire un JWT con dati arbitrari, che può portare ad esempio a furti di account ed elevazione dei privilegi.

Questa vulnerabilità può presentarsi quando la libreria usata per la validazione dei JWT si affida totalmente all'algoritmo presente nell'header, invece che controllare che sia concorde con quanto specificato dallo sviluppatore. Ultimamente, per eliminare questa classe di bug, le librerie di JWT hanno completamente eliminato la possibilità di utilizzare questo algoritmo, oppure richiedono un flag esplicito per abilitarne la decodifica.

Algorithm confusion

Alcune librerie JWT sono vulnerabili a algorithm confusion se si cambia il valore dell'algoritmo da RS256 a HS256. L'idea è che possiamo interpretare la chiave pubblica (asimmetrica) come una chiave condivisa (simmetrica) grazie alla mancanza di controlli opportuni.

L'attacco funziona come segue:

  • l'applicazione web verifica il JWT usando la chiave pubblica dato che l'algoritmo è RS256,
  • l'utente malevolo ha accesso alla chiave pubblica, in quanto pubblica, quindi può costruire un JWT con algoritmo HS256 usando la chiave pubblica come segreto,
  • il server vedrà l'algoritmo HS256 ma passerà la chiave pubblica, quindi userà quel valore come segreto per fare HMAC.