Per lungo tempo sono stati uti­liz­za­ti i cookie per l’au­ten­ti­ca­zio­ne degli utenti sul web. Ancora oggi, questo metodo funziona molto bene, so­prat­tut­to per quanto riguarda certe ap­pli­ca­zio­ni. Ma a volte è ne­ces­sa­ria una maggiore fles­si­bi­li­tà. Qui entra in gioco JSON Web Token. Il nuovo standard aperto è adottato sempre più di frequente dai prin­ci­pa­li siti web e ap­pli­ca­zio­ni. In questo articolo vi mostriamo cos’è JWT, come funziona e dove viene applicato.

Cos’è un JSON Web Token?

Un JSON Web Token è un token di accesso stan­dar­diz­za­to secondo RFC 7519 e consente lo scambio sicuro di dati tra due parti. Contiene tutte le in­for­ma­zio­ni im­por­tan­ti su un’entità, in modo che non sia ne­ces­sa­ria alcuna in­ter­ro­ga­zio­ne del database e che la sessione non debba essere me­mo­riz­za­ta sul server (stateless session).

I JSON Web Token sono quindi par­ti­co­lar­men­te popolari nei processi di au­ten­ti­ca­zio­ne. I brevi messaggi possono essere criptati e quindi fornire in­for­ma­zio­ni sicure su chi è il mittente e se lo stesso sia dotato dei permessi di accesso necessari. Gli utenti stessi entrano in contatto con il token solo in­di­ret­ta­men­te, ad esempio inserendo il proprio nome utente e la password in una maschera. La co­mu­ni­ca­zio­ne effettiva avviene tra le varie ap­pli­ca­zio­ni lato client e server.

Struttura di un JSON Web Token

Un JWT firmato è composto da tre parti, ciascuna co­di­fi­ca­ta con Base64 e separata da un punto:

HEADER.PAYLOAD.SIGNATURE

Cosa si­gni­fi­ca­no queste tre parti? Di seguito ve le il­lu­stria­mo sin­go­lar­men­te.

Header

L’header è composto da due parti e fornisce im­por­tan­ti in­for­ma­zio­ni sul token. Contiene il tipo di token e l’algoritmo di firma e/o crit­to­gra­fia uti­liz­za­to. Un esempio di header JWT può essere il seguente:

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

Il tipo rac­co­man­da­to è sempre JWT. Descrive il tipo di supporto IANA"ap­pli­ca­tion/jwt". Nell’esempio sopra riportato, l’in­te­sta­zio­ne specifica che HMAC-SHA256, ab­bre­via­to in "HS256", viene uti­liz­za­to per firmare il token. Ulteriori metodi di cifratura tipici sono RSA con SHA-256 ("RS256") ed ECDSA con SHA-256 ("ES256"). Si scon­si­glia l’uso della crit­to­gra­fia. Tuttavia, se i dati non hanno un elevato fattore di pro­te­zio­ne, può essere spe­ci­fi­ca­to "none" come cifratura. I valori possibili sono stan­dar­diz­za­ti da JSON Web En­cryp­tion (JWE) secondo RFC 7516.

Per i JSON Web Token più complessi, firmati o criptati, c’è un parametro ag­giun­ti­vo "cty" per "content type". Può essere riempito anche con il valore "JWT". In tutti gli altri casi, questo parametro viene omesso.

Payload

La sezione Payload del JSON Web Token è la posizione che contiene le in­for­ma­zio­ni effettive che devono essere inviate all’ap­pli­ca­zio­ne. Qui si de­fi­ni­sco­no alcuni standard che spe­ci­fi­ca­no cosa e come si tra­smet­to­no de­ter­mi­na­ti dati. Le in­for­ma­zio­ni sono fornite come coppie key/value, dove le chiavi in JWT sono chiamate claim. Ci sono tre diversi tipi di claim:

  • claim re­gi­stra­ti all’interno del IANA JSON Web Token Claim Register e il cui scopo è definito in uno standard. Alcuni esempi sono l’emittente del token ("iss" per issuer), il dominio di de­sti­na­zio­ne ("aud" per audience) e il tempo di scadenza ("exp" per ex­pi­ra­tion time). Per mantenere la lunghezza del token il più breve possibile, sono stati uti­liz­za­ti nomi di claim brevi.
  • Claim pubblici, de­fi­ni­bi­li a proprio pia­ci­men­to senza re­stri­zio­ne. Per evitare col­li­sio­ni nella semantica delle keys, è ne­ces­sa­rio re­gi­stra­re pub­bli­ca­men­te i claim nel relativo registro dei claim dei JSON Web Token IANA o assegnare nomi re­si­sten­ti alle col­li­sio­ni.
  • Claim privati sono pensati per in­for­ma­zio­ni da scambiare spe­ci­fi­ca­ta­men­te con la propria ap­pli­ca­zio­ne. Mentre i claim pubblici con­ten­go­no in­for­ma­zio­ni come "name" o "e-mail", quelli privati sono più specifici. Un’in­for­ma­zio­ne tipica è un "ID utente" o uno specifico "nome del reparto". È im­por­tan­te as­si­cu­rar­si che il nome non si scontri con i claim re­gi­stra­ti o pubblici.

Tutti i claim sono fa­col­ta­ti­vi, pertanto non è ne­ces­sa­rio uti­liz­za­re ciascun claim re­gi­stra­to. In generale, i payload utili possono contenere qualsiasi numero di claim, ma è con­si­glia­bi­le limitare le in­for­ma­zio­ni nel JWT allo stretto ne­ces­sa­rio. Più grande è il JWT, più risorse richiede per la (de)codifica.

Il payload può quindi avere la seguente struttura:

{ "sub": "123", "name": "Alice", "exp": 30 }

Signature

La firma di un JSON Web Token è creata uti­liz­zan­do la codifica Base64 dell’header e del payload e il metodo di firma/codifica spe­ci­fi­ca­to. La struttura è definita dalla JSON Web Signature (JWS), uno standard secondo RFC 7515. Affinché la firma funzioni, è ne­ces­sa­rio uti­liz­za­re una chiave segreta nota solo all’ap­pli­ca­zio­ne originale. Da un lato, questa firma verifica che il messaggio non sia stato mo­di­fi­ca­to durante il percorso e dall’altro, se il token è firmato con una chiave privata, assicura che il mittente del JWT sia quello corretto.

A seconda della sen­si­bi­li­tà dei dati, ci sono diverse procedure:

  1. Nessun backup: come pre­ce­den­te­men­te accennato, se il fattore di pro­te­zio­ne dei dati è basso, può essere spe­ci­fi­ca­to il valore "none" nell’ header. In questo caso non viene generata alcuna firma. Quindi il JSON Web Token consiste solo di header e payload. Senza pro­te­zio­ne, il payload è leggibile in chiaro dopo la de­co­di­fi­ca di Base64 e non viene ve­ri­fi­ca­to se il messaggio provenga dal mittente corretto o se sia stato mo­di­fi­ca­to in itinere.
  2. Firma (JWS): in genere è suf­fi­cien­te con­trol­la­re se i dati pro­ven­ga­no dal mittente corretto e se siano stati mo­di­fi­ca­ti durante il percorso. Questo viene fatto uti­liz­zan­do lo schema JSON Web Signature (JWS), che assicura che il messaggio non sia stato mo­di­fi­ca­to durante il trasporto e che provenga dal mittente corretto. Con questa procedura, il carico utile può essere letto in chiaro anche dopo la de­crit­ta­zio­ne di Base64.
  3. Firma (JWS) e crit­to­gra­fia (JWE): è possibile uti­liz­za­re una JSON Web En­cryp­tion (JWE) in aggiunta al JWS. JWE cripta il contenuto del payload, che viene suc­ces­si­va­men­te firmato con JWS. Per decifrare il contenuto, viene spe­ci­fi­ca­ta una password comune o una chiave privata. Il mittente è quindi ve­ri­fi­ca­to, il messaggio è riservato e autentico e il payload non può essere letto in chiaro dopo la de­crit­ta­zio­ne di Base64.

Il processo di cifratura dà come risultato una sequenza di caratteri ap­pa­ren­te­men­te casuale:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
N.B.

Per ciascuna delle procedure sopra men­zio­na­te, durante la co­mu­ni­ca­zio­ne si dovrebbe in aggiunta uti­liz­za­re l’SSL, così da pro­teg­ge­re i dati.

Come funziona un JSON Web Token?

La funzione del JSON Web Token può essere spiegata molto bene con un login utente. Prima di uti­liz­za­re il JWT, è ne­ces­sa­rio definire una chiave segreta (secret). Una volta che un utente ha inserito con successo i propri dati di accesso, il JWT viene re­sti­tui­to con la chiave e me­mo­riz­za­to in locale. La tra­smis­sio­ne dovrebbe essere ef­fet­tua­ta tramite HTTPS per pro­teg­ge­re meglio i dati.

Ogni volta che l’utente desidera accedere a risorse protette, ad esempio a un’API, o a un percorso protetto, lo User Agent invia il JWT come parametro (ad esempio ‘jwt’ per le GET request) o come in­te­sta­zio­ne di au­to­riz­za­zio­ne (per POST, PUT, OPTIONS, DELETE). Il partner di co­mu­ni­ca­zio­ne è in grado di decifrare il JSON Web Token e, se il controllo va a buon fine, eseguire la richiesta.

N.B.

Dal momento che il JSON Web Token è un dato di accesso, non si deve tenere il token più a lungo del ne­ces­sa­rio e non si devono me­mo­riz­za­re dati sensibili nella memoria del browser.

Dove si applica il JSON Web Token?

JSON Web Token offre diversi vantaggi rispetto al tra­di­zio­na­le metodo di au­ten­ti­ca­zio­ne e au­to­riz­za­zio­ne basato su cookie e viene uti­liz­za­to, tra l’altro, nei seguenti scenari:

  1. Ap­pli­ca­zio­ni REST: nelle ap­pli­ca­zio­ni REST, il JWT assicura che l’ap­pli­ca­zio­ne sia priva di stato, inviando le in­for­ma­zio­ni di au­ten­ti­ca­zio­ne di­ret­ta­men­te con la richiesta.
  2. Cross-Origin Ressource Sharing: JSON Web Token invia in­for­ma­zio­ni durante la con­di­vi­sio­ne di risorse cross-origin. Questo ha un enorme vantaggio rispetto ai cookie, che di solito non vengono inviati con questo metodo.
  3. Utilizzo di più framework: JSON Web Token è stan­dar­diz­za­to e può essere uti­liz­za­to più volte Quando si uti­liz­za­no più framework, è più facile con­di­vi­de­re i dati di au­ten­ti­ca­zio­ne.

Come si im­ple­men­ta nella pratica un esempio di JWT?

Ri­cor­ren­do a un esempio di JWT, vogliamo mostrarvi come si presenta il token. A questo scopo, useremo l’header di esempio che abbiamo già men­zio­na­to all’inizio:

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

L’aspetto del payload del JSON Web Token potrebbe dunque essere simile a questo:

{
	"sub": "0123456789",
	"name": "Mario Rossi",
	"admin": true
}

Per ottenere l’effettiva struttura del JWT (tre parti separate da punti), l’header e il payload devono essere co­di­fi­ca­ti con Base64. L’header sarà quindi come di seguito:

base64Header = base64Encode(header)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Allo stesso modo sarà im­ple­men­ta­to nel payload:

base64Payload = base64Encode(payload)
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Ora non resta che creare la firma. Nell’header abbiamo indicato che la firma è HMAC-SHA256:

signature = HS256(base64Header + '.' + base64Payload, 'secret')
// dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

L’ultimo passo è quello di unire queste tre parti insieme e separarle con un punto:

Token = base64Header + ‘.’ + base64Payload + ‘.’ + signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Ad oggi, la maggior parte dei linguaggi di pro­gram­ma­zio­ne fornisce librerie per la ge­ne­ra­zio­ne di JSON Web Token, pertanto non è più ne­ces­sa­ria l’im­ple­men­ta­zio­ne manuale.

Vai al menu prin­ci­pa­le