In questa lezione, esploreremo uno degli strumenti fondamentali nell'autenticazione e nella gestione delle sessioni utente nelle applicazioni moderne: i JSON Web Tokens (JWT). Vedremo cosa sono, come funzionano e perché vengono usati per garantire la sicurezza e la gestione delle informazioni tra il client e il server. Inoltre, discuteremo i principali vantaggi nell'adozione di JWT per la protezione delle API e l'autenticazione degli utenti.
Cos'è un JSON Web Token
OAuth 2.0 non specifica un formato per il token ma in molti casi il formato scelto per l'access token è un JWT. In questo caso, JWT è usato come il formato per l'access token in un flusso OAuth 2.0. Quindi, la correlazione è che OAuth 2.0 gestisce l'autorizzazione e JWT viene usato per il trasporto sicuro delle informazioni relative a quell'autorizzazione.
Ecco come si interconnettono:
- OAuth 2.0 gestisce l'autorizzazione: il flusso di come un'app ottiene l'accesso a risorse protette per conto dell'utente.
- JWT viene utilizzato come formato per l'access token in questo flusso, consentendo al server di verificare facilmente l'autenticità e l'integrità dell'accesso.
In altre parole, OAuth 2.0 è il protocollo che stabilisce come un'applicazione può ottenere accesso a risorse protette, mentre JWT è spesso utilizzato per rappresentare l'accesso in modo sicuro. Un JSON Web Token è quindi un formato compatto, URL-safe per rappresentare dichiarazioni (claims) tra due parti. I JWT sono comunemente utilizzati per l'autenticazione e l'autorizzazione nelle applicazioni web moderne. Ognuno di essi è composto da tre sezioni principali:
-
Header: contiene informazioni sulla modalità di firma del token, come il tipo di token (JWT) e l'algoritmo di firma utilizzato, ad esempio
HS256
(HMAC con SHA-256) oRS256
(RSA con SHA-256). -
Payload: contiene le dichiarazioni (claims) che possono essere informazioni sull'utente o altri dati. Esse possono essere di tre tipi:
- Registered Claims: claims predefiniti che sono standardizzati, come
sub
(soggetto),iat
(timestamp di emissione),exp
(timestamp di scadenza). - Public Claims: claims che possono essere definiti liberamente ma che devono essere registrati o evitare collisioni di nome.
- Private Claims: claims definiti specificamente per un'applicazione, utilizzati per scopi interni e non condivisi pubblicamente.
- Registered Claims: claims predefiniti che sono standardizzati, come
-
Signature: la firma serve a garantire che il token non sia stato alterato. Per creare la firma si usa una chiave segreta con l'algoritmo scelto (come HMAC SHA-256) o una chiave privata (RSA o ECDSA).
Questa struttura permette di trasferire informazioni in modo sicuro e verificabile tra il client e il server senza la necessità di mantenere sessioni server-side persistenti.
Come funzionano i JWT
Il flusso di lavoro di un JWT di solito coinvolge i seguenti passaggi:
- Autenticazione dell'utente: l'utente invia le sue credenziali (nome utente e password) al server.
- Generazione del JWT: se le credenziali sono corrette, il server genera un JWT firmato contenente le informazioni dell'utente, come il suo ID, il ruolo, e un timestamp di scadenza.
- Invio del JWT al client: il JWT viene inviato al client che lo memorizza tipicamente in un cookie o nel local storage.
- Autorizzazione nelle richieste successive: nelle richieste future il client invia il JWT nel header HTTP (usualmente nel campo
Authorization
con il prefissoBearer
), permettendo al server di autenticare l'utente senza bisogno di nuove credenziali. - Verifica del JWT: ogni volta che il server riceve un JWT lo verifica usando la chiave segreta o la chiave pubblica, a seconda dell'algoritmo scelto. Se la firma è valida e il token non è scaduto il server può concedere l'accesso alla risorsa richiesta.
Perché usare JWT
I JWT offrono diversi vantaggi nell'ambito dell'autenticazione e dell'autorizzazione:
-
Stateless Authentication: una delle caratteristiche principali dei JWT è che sono stateless, il che significa che il server non ha bisogno di memorizzare alcuna informazione sulle sessioni utente. Tutte le informazioni necessarie sono contenute nel token stesso riducendo il carico del server e migliorando la scalabilità.
-
Scalabilità: poiché i JWT sono autonomi e non richiedono sessioni persistenti sul server, le applicazioni che li utilizzano possono scalare facilmente su più server senza preoccuparsi della sincronizzazione dello stato della sessione.
-
Sicurezza: i JWT sono firmati digitalmente, quindi è praticamente impossibile che vengano modificati durante il transito senza che il server possa rilevarlo. Inoltre, se si utilizza la crittografia, possono essere anche cifrati per garantire la riservatezza dei dati.
-
Flessibilità e portabilità: essendo basati su JSON sono facilmente leggibili e manipolabili da qualsiasi linguaggio di programmazione che supporta tale formato. Inoltre, essendo URL-safe, possono essere facilmente trasmessi tramite URL, cookie, o intestazioni HTTP.
-
Supporto per Single Sign-On (SSO): sono spesso usati in contesti di Single Sign-On (SSO), dove un utente può autenticarsi una volta e ottenere l'accesso a molteplici applicazioni senza doversi ri-autenticare.
Creazione di un JSON Web Token
Per creare un JWT, bisogna seguire questi passaggi:
-
Costruire l'header che contiene almeno due parti: il tipo del token e l'algoritmo di firma, come
HS256
.
{ "alg": "HS256", "typ": "JWT"}
Costruire il payload che contiene le dichiarazioni. Ecco un esempio di payload con una dichiarazione sub
(soggetto) e exp
(data di scadenza):
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022, "exp": 1516239022 + 3600}
-
Creare la firma che viene generata utilizzando l'algoritmo specificato nell'header e la chiave segreta. Ad esempio, se si usa HMAC SHA-256, la firma sarà una stringa ottenuta applicando l'algoritmo alla combinazione di
base64url_encode(header)
,base64url_encode(payload)
e la chiave segreta.La firma assicura che il contenuto non venga alterato.
-
Comporre il token. Infine, si concatenano le tre parti codificate in base64url, separate da punti (
.
), per ottenere il JWT finale:
header.payload.signature
Quando un server riceve un JWT, deve verificare che:
- Il JWT non sia scaduto (
exp
). - La firma sia valida, utilizzando la chiave segreta o la chiave pubblica appropriata per l'algoritmo di firma.
- Eventuali altre condizioni di sicurezza siano soddisfatte (ad esempio, che il
sub
del JWT corrisponda all'utente che sta facendo la richiesta).
Vantaggi e svantaggi
Tra i vantaggi abbiamo:
- Autonomia: il server non ha bisogno di memorizzare le sessioni utente.
- Portabilità: i JWT sono facilmente trasportabili su diverse piattaforme e possono essere utilizzati su più domini.
- Sicurezza: la firma digitale garantisce che il token non sia stato alterato.
Ecco invece gli svantaggi:
- Dimensioni: i JWT possono diventare relativamente grandi, soprattutto se contengono molte dichiarazioni.
- Revoca: poiché il server non memorizza lo stato del token, non è facile revocare un JWT prima della sua scadenza, a meno che non si implementi un sistema di blacklist.
- Gestione della scadenza: hanno una durata limitata e richiedono la gestione della scadenza e del rinnovo.
Conclusioni
I JSON Web Tokens sono uno strumento fondamentale per l'autenticazione e la protezione delle API nelle applicazioni moderne. Offrono numerosi vantaggi in termini di scalabilità, sicurezza e flessibilità, rendendo facile implementare meccanismi di autenticazione stateless. È però importante considerare anche i loro svantaggi, come la gestione della scadenza e della revoca, e bilanciarli con le esigenze della propria applicazione.
Con una corretta implementazione i JWT possono semplificare notevolmente la gestione della sicurezza nelle applicazioni web e mobile.