Cos’è il JWT? I token Web JSON spiegati con un esempio funzionante
Un JWT consente a un server di fidarsi di una richiesta senza cercare nulla. Costruiscine uno da zero, prova a manometterlo e guardalo fallire, quindi scopri quando i token battono le sessioni e come usarli in sicurezza.
- Un JWT è un token compatto e firmato composto da tre parti: intestazione, carico utile e firma.
- La firma dimostra che un token non è stato modificato, quindi il server può fidarsi di esso senza alcuna ricerca.
- Il payload è leggibile da chiunque, quindi non inserire mai segreti.
- I token sono difficili da revocare, quindi mantienili di breve durata e verificali con una libreria attendibile.
Dopo aver effettuato l’accesso, come fa un server a sapere che ogni richiesta successiva proviene davvero da te? Una risposta popolare è un JSON Web Token, o JWT, solitamente pronunciato “jot”. Si tratta di un piccolo dato firmato che il client invia con ogni richiesta e il server può controllarlo senza toccare un database.
Il modo più veloce per comprendere un JWT è costruirne uno e poi provare a romperlo. Lo abbiamo fatto utilizzando solo la libreria standard di Python, su Python 3.13, e l’output seguente proviene da quell’esecuzione. Questo codice è per l’apprendimento. In un’applicazione reale, utilizzare una libreria ben mantenuta, perché i dettagli della verifica sono facili da sbagliare.
Cos’è un JWT?
JWT è uno standard aperto, definito nella RFC 7519, per il passaggio delle rivendicazioni tra due parti come una stringa compatta. Un’attestazione è semplicemente un’affermazione, ad esempio “l’ID di questo utente è 42”. Poiché il token è firmato, il destinatario può confermare chi lo ha emesso e che nessuno lo ha modificato.
Pensa a un braccialetto da festival. Il personale al gate controlla il tuo biglietto una volta e ti dà una fascia difficile da falsificare. Dopodiché ogni stallo guarda solo la band, senza bisogno di telefonare alla biglietteria. Un JWT funziona più o meno allo stesso modo per un’API.
Come funziona l’accesso JWT
- L’utente invia un nome utente e una password all’endpoint di accesso.
- Il server li controlla e crea un token firmato.
- Il client memorizza il token.
- Ogni richiesta successiva lo include, in genere in un’intestazione:
Authorization: Bearer <token>. - Il server verifica la firma e la scadenza, quindi legge le attestazioni.
Il vantaggio principale si trova nel passaggio 5. Il server non deve cercare una sessione, il che è utile quando molti servizi o server devono controllare lo stesso token. Se non conosci le API, inizia con cos’è un’API.
Le tre parti di un JWT
Un JWT sembra testo casuale, ma è composto da tre sezioni con codifica Base64URL separate da punti. Eccone uno che abbiamo generato:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI0MiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzkzNTAwMDAwLCJleHAiOjE3OTM1MDA5MDB9
.7YfUDH_T-iDh8bMmUT8mmKYwOstzT8Ty--DTTAmQGWM
Abbiamo aggiunto interruzioni di riga per facilitare la lettura. La decodifica delle prime due parti fornisce un semplice JSON:
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"42","role":"user","iat":1793500000,"exp":1793500900}
| Parte | Contiene | Scopo |
|---|---|---|
| Intestazione | Tipo di token e algoritmo di firma | Spiega come verificare il token |
| Carico utile | Affermazioni sull’utente o sulla sessione | Le informazioni reali |
| Firma | Un hash delle prime due parti, utilizzando una chiave | Dimostra l’integrità e la provenienza |
Affermazioni standard
| Richiedi | Nome | Significato |
|---|---|---|
sost |
Oggetto | Chi riguarda il token, solitamente un ID utente |
iss |
Emittente | Chi ha creato il token |
aud |
Pubblico | A chi è destinato il token |
esp |
Scadenza | Quando il token smette di essere valido |
iat |
Rilasciato a | Quando è stato creato |
nbf |
Non prima | Quando inizia ad essere valido |
jti |
ID JWT | Un ID univoco per questo token |
Puoi anche aggiungere attestazioni personalizzate, come role. I tempi sono timestamp Unix, in secondi. Mantieni piccolo il carico utile, poiché il token viaggia con ogni richiesta.
Costruiscine uno tu stesso
La creazione di un token implica la codifica delle due parti JSON e la successiva firma con un segreto utilizzando HMAC-SHA256:
import base64, hashlib, hmac, json
SECRET = b"demo-secret-do-not-use-in-production"
def b64url(data):
return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
def sign(message):
return b64url(hmac.new(SECRET, message.encode(), hashlib.sha256).digest())
def create_token(payload):
header = {"alg": "HS256", "typ": "JWT"}
parts = [
b64url(json.dumps(header, separators=(",", ":")).encode()),
b64url(json.dumps(payload, separators=(",", ":")).encode()),
]
message = ".".join(parts)
return message + "." + sign(message)
La verifica funziona ricalcolando la firma e confrontandola con quella nel token. Solo qualcuno con il segreto può produrne uno corrispondente:
def verify_token(token, now):
header, payload, signature = token.split(".")
expected = sign(header + "." + payload)
if not hmac.compare_digest(signature, expected):
raise ValueError("bad signature")
claims = json.loads(b64url_decode(payload))
if claims["exp"] < now:
raise ValueError("token expired")
return claims
Un token valido ha restituito le proprie attestazioni come previsto. compare_digest viene utilizzato poiché funziona in tempo costante, il che evita perdite di informazioni a causa di differenze temporali.
Prova a manometterlo
Supponiamo che un utente malintenzionato decodifichi il payload, cambi "role":"user" in "role":"admin", lo codifichi nuovamente e mantenga la vecchia firma. Abbiamo provato questo, insieme ad altri due attacchi:
| Tentativo | Risultato |
|---|---|
| Modificato il ruolo in amministratore | pessima firma |
| Utilizzato il token 1 secondo dopo la scadenza | token scaduto |
Impostato "alg":"none" e rimosso la firma |
pessima firma |
Quest’ultimo tentativo prende di mira una vera debolezza storica. Alcune librerie una volta si fidavano dell’intestazione del token, quindi un utente malintenzionato poteva semplicemente dichiarare che non era necessaria alcuna firma. Il nostro codice utilizza sempre un algoritmo fisso, motivo per cui è stato rifiutato. In una biblioteca reale, specifica sempre gli algoritmi che accetti.
Firmato, non crittografato
Questo è il punto più frainteso sui JWT. Il nostro token contraffatto è stato rifiutato, ma il suo contenuto era ancora perfettamente leggibile:
{"sub":"42","role":"admin","iat":1793500000,"exp":1793500900}
Base64URL è una codifica, non una crittografia, e chiunque può invertirla senza alcuna chiave. La firma impedisce alle persone di modificare i dati, ma non di leggerli. Quindi non inserire mai password, numeri di carta o dati personali privati in un payload JWT. Se i contenuti devono essere nascosti, utilizzare token crittografati (JWE) o semplicemente conservare i dati sul server.
HS256 contro RS256
| Aspetto | HS256 | RS256 o ES256 |
|---|---|---|
| Digitare | Simmetrico | Asimmetrico |
| Chiavi | Un segreto condiviso | Una chiave privata firma, una chiave pubblica verifica |
| Chi può creare token | Chiunque detenga il segreto | Solo il titolare della chiave privata |
| Meglio per | Un servizio o un piccolo gruppo fidato | Molti servizi, terze parti, fornitori di identità |
Con la firma asimmetrica, altri servizi possono verificare i token senza poterne coniare di propri, il che limita il danno se uno viene compromesso.
JWT vs sessioni
I JWT sono spesso presentati come un moderno sostituto delle sessioni. In realtà, ognuno ha dei compromessi:
| Aspetto | Sessione del server | JWT |
|---|---|---|
| Dove vive lo Stato | Sul server | Nel gettone |
| Ricerca su ogni richiesta | Di solito | Non necessario |
| Disconnessione o revoca | Facile, elimina la sessione | Difficile prima della scadenza |
| Dimensioni per richiesta | Carta d’identità piccola | Token più grande (il nostro era di 161 caratteri) |
| Attraverso molti servizi | Necessita di spazio di archiviazione condiviso | Ciascuno può verificarlo direttamente |
| Modifica delle autorizzazioni | Si applica immediatamente | Il vecchio token rimane valido fino alla scadenza |
Per un sito Web tradizionale reso dal server, un cookie di sessione è spesso più semplice e sicuro. I JWT tendono ad avere più senso per le API utilizzate da diversi servizi o per i client mobili.
Suggerimento: Non scegliere JWT solo perché sembra apolide. Molti sistemi reali aggiungono una lista nera o un controllo del database per supportare il logout, il che riporta la ricerca che JWT avrebbe dovuto evitare.
Dove archiviare i token in un browser
| Posizione | Rischio XSS | Rischio CSRF | Note |
|---|---|---|---|
localStorage |
Alto, come possono leggerlo gli script | Basso | Semplice, ma esposto a qualsiasi script iniettato |
| Cookie HttpOnly | Più basso, poiché gli script non possono leggerlo | Ha bisogno di protezione | Utilizzare Secure e SameSite |
| Variabile in memoria | Più in basso | Basso | Perso durante l’aggiornamento, quindi è necessario un flusso di aggiornamento |
Molte guide sulla sicurezza preferiscono HttpOnly, Secure, SameSite i cookie per le app web. Qualunque cosa tu scelga, usa sempre HTTPS. Per inviare un token da JavaScript, consulta il nostro tutorial sull’API JavaScript Fetch.
Aggiorna i token
La scadenza breve limita il danno derivante da un token rubato, ma nessuno vuole accedere ogni 15 minuti. La solita soluzione utilizza due token:
- Token di accesso: di breve durata, ad esempio minuti, e inviato con ogni richiesta API.
- Token di aggiornamento: di più lunga durata, archiviato con maggiore attenzione e utilizzato solo per ottenere nuovi token di accesso.
Il server tiene traccia dei token di aggiornamento, quindi può revocarli, il che ti offre un pratico logout. Ruotarli a ogni utilizzo ti aiuta anche a rilevare il furto, perché un vecchio token rubato viene riprodotto.
Errori comuni di sicurezza
- Decodifica senza verifica. La lettura di un payload non lo rende affidabile. Controlla sempre la firma.
- Accetta qualsiasi algoritmo. Imposta un elenco esplicito di algoritmi consentiti.
- Utilizzo di un segreto debole. I segreti brevi possono essere violati offline. Utilizzare un valore casuale lungo e mantenerlo fuori dal controllo del codice sorgente.
- Saltare la scadenza. I token senza
exppossono funzionare per sempre se rubati. - Non controllare
isseaud. Altrimenti un token emesso per un servizio potrebbe essere accettato da un altro. - Affidarsi ad affermazioni obsolete. Un ruolo all’interno di un token può non essere aggiornato fino alla scadenza.
- Token di registrazione. Chiunque legga i tuoi log potrebbe riutilizzarli.
- Non testare i percorsi di errore. Aggiungi test per i token scaduti e modificati, nonché per quelli validi. La nostra guida Test API con Postman può aiutarti.
Considerazioni finali
Un JWT è un dato firmato di cui un server può fidarsi senza una ricerca, non un contenitore segreto e non un aggiornamento automatico durante le sessioni. Utilizza una scadenza breve, verifica tutto con una libreria mantenuta e mantieni i dati privati fuori dal carico utile. Per vederlo di persona, esegui un piccolo script come il nostro, cambia un carattere di un token e guarda la verifica fallire.
Domande frequenti
A cosa serve un JWT?
I JWT vengono utilizzati principalmente per l’autenticazione e l’autorizzazione nelle API. Dopo l’accesso, un client invia il token con ogni richiesta e il server lo verifica per identificare l’utente.
Un JWT è crittografato?
Di solito no. Un JWT standard è firmato e codificato, quindi chiunque può leggerne il carico utile. La firma impedisce solo le modifiche. I token crittografati utilizzano un formato correlato chiamato JWE.
Quanto dovrebbe durare un JWT?
I token di accesso sono generalmente di breve durata, spesso minuti anziché giorni. Abbinateli a un token di aggiornamento, in modo che gli utenti non debbano accedere costantemente.
È possibile revocare un JWT?
Non da solo, poiché rimane valido fino alla scadenza. La revoca richiede il monitoraggio lato server, come una lista nera, che rimuove parte del vantaggio stateless.
JWT è migliore delle sessioni?
Nessuno dei due è sempre migliore. Le sessioni sono più semplici da revocare e si adattano a molti siti Web, mentre i JWT sono adatti ad API e servizi che devono verificare l’identità in modo indipendente.
Continua a imparare
Hai bisogno di aiuto con test, WordPress o SEO?
Aiutiamo i team a fornire software migliore e a far crescere i loro siti. Raccontaci a cosa stai lavorando e ti suggeriremo chiaramente il prossimo passo.
Altre guide su test, intelligenza artificiale e sviluppo moderno
Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.
Spiegazione delle allucinazioni dell'intelligenza artificiale: perché i modelli linguistici inventano le cose e come ridurle
Spiegazione delle allucinazioni dell'intelligenza artificiale: cosa sono, perché i modelli linguistici le producono, tipi comuni, come ridurle con b…
Leggi l'articolo →DevOpsSpiegazione delle variabili d'ambiente: file .env, segreti e configurazione eseguiti correttamente
Variabili d'ambiente spiegate con esempi Python che abbiamo eseguito: lettura e impostazione, perché ogni valore è una stringa, file .env, ereditari…
Leggi l'articolo →Sviluppo softwareSpiegazione della limitazione della velocità API: algoritmi, intestazioni e gestione degli errori 429
La limitazione della velocità dell'API spiegata con una simulazione che abbiamo eseguito: bucket di token, finestra fissa, finestra scorrevole, risp…
Leggi l'articolo →Automazione dei testDerisione in Python: unittest.mock, patch e gli errori che fanno mentire i test
Mocking in Python con unittest.mock, testato: Mock e return_value, side_effect, patch dove viene utilizzato un nome, specifiche e autospec, date moc…
Leggi l'articolo →Test del softwareSpiegazione della copertura del codice: copertura di linea o di filiale e cosa significa realmente il 100%.
Copertura del codice spiegata con una vera esecuzione di cover.py: copertura di linea, ramo e condizione, lettura di un rapporto, perché la copertur…
Leggi l'articolo →Database e SQLDELETE vs TRUNCATE vs DROP in SQL: differenze, rollback e quando utilizzarli
DELETE vs TRUNCATE vs DROP spiegato con SQL testato: cosa rimuove, rollback, trigger, reimpostazione dell'identità, velocità e come differiscono Pos…
Leggi l'articolo →Database e SQLSpiegazione delle visualizzazioni SQL: crea, utilizza ed evita le insidie, con esempi
Viste SQL spiegate con le query che abbiamo eseguito: creazione di una vista, risultati in tempo reale, nascondere colonne, prestazioni, viste aggio…
Leggi l'articolo →Sviluppo softwareInterfaccia TypeScript e tipo: differenze reali, testate con il compilatore
Interfaccia TypeScript vs tipo, verificata con il vero compilatore: cosa possono fare entrambi, cosa può fare solo uno, fusione delle dichiarazioni,…
Leggi l'articolo →Sviluppo softwareSpiegazione di Python *args e **kwargs: funzioni flessibili con esempi chiari
Python *args e **kwargs spiegati con il codice che abbiamo eseguito: compressione e decompressione, ordine dei parametri, argomenti solo per parole …
Leggi l'articolo →Sviluppo softwareFunzioni Lambda Python: sintassi, usi reali e quando non usarli
Funzioni lambda Python spiegate con il codice che abbiamo eseguito: sintassi, ordinamento con chiave, mappa e filtro, chiusure, trap dell'associazio…
Leggi l'articolo →Intelligenza artificialeCosa sono gli agenti AI? Come funzionano, con un semplice ciclo di agenti che puoi eseguire
Cosa sono gli agenti IA? Una semplice guida al ciclo dell'agente, agli strumenti, alla memoria e ai guardrail, con un piccolo ciclo Python che abbia…
Leggi l'articolo →DevOpsMonitoraggio vs osservabilità: la vera differenza, con log, metriche e tracce
Spiegazione del monitoraggio e dell'osservabilità: errori noti e sconosciuti, log, metriche e tracce, una procedura dettagliata sugli incidenti di p…
Leggi l'articolo →DevOpsVolumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto
Volumi Docker e montaggi di collegamento spiegati: perché i dati del contenitore scompaiono, volumi denominati, montaggi di collegamento, tmpfs, ese…
Leggi l'articolo →Automazione dei testTDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno
TDD vs BDD spiegato con una funzione di sconto costruita in entrambi i modi: refactoring rosso-verde con il codice che abbiamo eseguito, scenari "Da…
Leggi l'articolo →Test del softwareTest di accettazione da parte dell'utente (UAT): processo, lista di controllo ed esempi reali
Spiegazione del test di accettazione dell'utente: chi lo esegue, in cosa differisce dal QA, un processo in sette fasi, un modello di test case UAT, …
Leggi l'articolo →Database e SQLSpiegazione dei valori SQL NULL: IS NULL, COALESCE, NULLIF e le trappole da evitare
Valori SQL NULL spiegati con le query che abbiamo eseguito: logica a tre valori, IS NULL, COALESCE, NULLIF, come aggregazioni, join e ordinamento tr…
Leggi l'articolo →Database e SQLIstruzione SQL CASE WHEN: sintassi, esempi reali ed errori comuni
SQL CASE WHEN spiegato con le query che abbiamo eseguito: moduli semplici e cercati, ordine delle condizioni, pivot con SUM, trucchi COUNT, ordiname…
Leggi l'articolo →Sviluppo softwareCos'è il JWT? Token Web JSON spiegati con un esempio funzionante
Cos'è il JWT? Spiegazione dei token Web JSON: le tre parti, un token creato e manomesso nel codice che abbiamo eseguito, JWT e sessioni, archiviazio…
Leggi l'articolo →Sviluppo softwareSpiegazione del loop di eventi JavaScript: stack di chiamate, microtask e timer con esempi
Il ciclo di eventi JavaScript spiegato con il codice che abbiamo eseguito: stack di chiamate, code di attività e microtask, perché setTimeout 0 non …
Leggi l'articolo →Sviluppo softwareSpiegazione dei generatori Python e del rendimento: risparmia memoria con esempi reali
Generatori Python e rendimento spiegati con il codice che abbiamo eseguito: come vengono messi in pausa e ripresi, misurato il risparmio di memoria,…
Leggi l'articolo →Intelligenza artificialeCosa sono gli incorporamenti? I vettori e la somiglianza del coseno spiegati semplicemente
Cosa sono gli incorporamenti? Una guida in linguaggio semplice ai vettori, alla similarità del coseno e alla ricerca semantica, con un piccolo esemp…
Leggi l'articolo →DevOpsDistribuzione blu-verde rispetto a quella canaria: differenze, compromessi e come scegliere
Spiegazione della distribuzione blu-verde e canary: come funziona ciascuna, costi, rischi e rollback, bucket utente stabile che abbiamo testato, mig…
Leggi l'articolo →Automazione dei testTest instabili: quali sono le cause e come risolverli definitivamente
Test instabili spiegati con demo che abbiamo eseguito: le cause principali, come confermarne e diagnosticarne uno, soluzioni adeguate per tempistich…
Leggi l'articolo →Test del softwareTest di carico e test di stress: differenze, metriche ed esempi k6
Spiegazione del test di carico e dello stress test: cosa dimostra ciascuno, test di picco e di assorbimento, le metriche che contano, perché le medi…
Leggi l'articolo →Test del softwareCaso di test e scenario di test: differenze chiave, esempi e quando utilizzarli
Spiegazione del caso di test e dello scenario di test: definizioni chiare, una tabella affiancata, una funzione di reimpostazione della password pre…
Leggi l'articolo →Database e SQLOttimizzazione delle query SQL: leggi i piani di esecuzione e correggi query lente, con tempistiche
Ottimizzazione delle query SQL testata su un milione di righe: leggi i piani di esecuzione, aggiungi gli indici corretti, correggi filtri non aggior…
Leggi l'articolo →Database e SQLSQL UNION vs UNION ALL: differenze, esempi e prestazioni testate
SQL UNION vs UNION ALL spiegati con le query che abbiamo eseguito: duplicati, regole seguite da entrambi, un vero bug di dati, prestazioni misurate,…
Leggi l'articolo →Sviluppo softwareTutorial sull'API di recupero JavaScript: GET, POST, gestione degli errori e timeout
Un tutorial sull'API JavaScript Fetch testato su un server locale: GET e POST, perché 404 non genera eccezioni, un helper riutilizzabile, stringhe d…
Leggi l'articolo →Sviluppo softwareGestione dei file Python: lettura, scrittura, CSV, JSON e pathlib con esempi
Gestione dei file Python spiegata con il codice che abbiamo eseguito: modalità aperte, con, lettura di file di grandi dimensioni, CSV, JSON, pathlib…
Leggi l'articolo →Sviluppo softwareClassi e oggetti Python: tutorial OOP con esempi reali
Classi e oggetti Python spiegati con il codice che abbiamo eseguito: __init__, metodi, attributi di classe e istanza, ereditarietà, proprietà, metod…
Leggi l'articolo →Intelligenza artificialeChe cos'è un modello linguistico di grandi dimensioni? Come funzionano i LLM, spiegato senza esagerazioni
Cos’è un modello linguistico ampio? LLM spiegati in un linguaggio semplice: token, incorporamenti, attenzione, formazione, finestre di temperatura e…
Leggi l'articolo →DevOpsComandi Linux per principianti: la guida essenziale del terminale con esempi
Comandi Linux per principianti, raggruppati per attività: navigazione, file, visualizzazione log, grep, pipe, permessi, processi e archivi, con un e…
Leggi l'articolo →Automazione dei testSelenio vs drammaturgo: differenze chiave, codice a confronto e quale scegliere
Selenium vs Playwright a confronto: architettura, attesa, supporto per browser e linguaggio, debug, lo stesso test in entrambi gli strumenti, consig…
Leggi l'articolo →Test del softwarePartizionamento di equivalenza: tecnica di progettazione dei test spiegata con esempi pratici
Spiegazione del partizionamento di equivalenza: come trovare partizioni valide e non valide, esempi funzionanti per età, password e coupon, test che…
Leggi l'articolo →Test del softwareGravità vs priorità nel test del software: differenze, matrice ed esempi reali
Spiegazione della gravità e della priorità nei test del software: definizioni chiare, una matrice a quattro vie con esempi, scale di livello, chi im…
Leggi l'articolo →Database e SQLEsercitazione sulle sottoquery SQL: tipi, sottoquery correlate ed EXISTS con esempi
Un tutorial sulle sottoquery SQL con le query che abbiamo eseguito: sottoquery scalari, IN, FROM e SELECT, sottoquery correlate, EXISTS, trap NOT IN…
Leggi l'articolo →Database e SQLSpiegazione di transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento
Transazioni SQL e ACID spiegate con un bonifico bancario eseguito: COMMIT, ROLLBACK, punti di salvataggio, blocchi, livelli di isolamento, letture s…
Leggi l'articolo →Sviluppo softwareGit merge vs rebase: differenze, esempi e quando usare ciascuno
Git merge vs rebase spiegato con output reale del log, una tabella di confronto, la regola d'oro del rebase e un flusso di lavoro sicuro per i team.
Leggi l'articolo →Sviluppo softwareList comprehension in Python: sintassi, esempi e quando evitarla
List comprehension in Python spiegata: sintassi, filtri, if-else, cicli annidati, tempi misurati e i casi in cui un normale ciclo for è meglio.
Leggi l'articolo →Database e SQLSQL JOIN spiegati con esempi (Inner, Left, Right, Full)
Capisci i JOIN SQL passo dopo passo con tabelle e query di esempio: INNER, LEFT, RIGHT, FULL, CROSS e SELF, con errori comuni e consigli sulle prest…
Leggi l'articolo →