Un JSON Web Token è composto da tre blocchi Base64url uniti da punti: header, payload e firma. Questo strumento li separa e ti mostra cosa contengono. Non controlla la firma, e l'omissione è voluta: il motivo vale due minuti del tuo tempo.
Decodificare non è verificare
Sono operazioni completamente diverse, e confonderle causa incidenti di sicurezza. Decodificare non richiede nulla: header e payload sono codificati in Base64url, non cifrati, quindi chiunque abbia il token legge ogni claim che contiene. Verificare richiede la chiave di firma, e risponde a una domanda diversa: questo token è stato davvero emesso da chi dice, e qualcuno l'ha modificato da allora?
Uno strumento che legge un token non dimostra niente sulla sua validità. Se incolli qui un token scaduto ne vedrai comunque il contenuto reso perfettamente. Il fatto che la decodifica riesca ti dice che la stringa è ben formata, niente di più.
Perché questo strumento si rifiuta di verificare le firme
Parecchi siti sui JWT offrono una casella per il tuo segreto di firma accanto al token. Pensa a cosa ti stanno chiedendo. Con HS256 il segreto è la stessa chiave che conia token validi: consegnalo a una pagina web e chi gestisce quella pagina può forgiare qualunque token voglia per il tuo sistema. Non esiste modo di verificare una firma simmetrica senza cedere anche la capacità di crearne.
Quindi questo strumento non te lo chiede, e faresti bene a diffidare di chi lo fa. Verifica le firme nel tuo codice, nel tuo runtime, con la chiave caricata dal tuo gestore di segreti. Una chiave di firma sta esattamente in due posti: il servizio che emette i token e quello che li controlla.
I claim su cui si inciampa
I timestamp sono i colpevoli abituali. La RFC 7519 definisce exp, iat e nbf come NumericDate: secondi dall'epoca Unix. Date.now() di JavaScript restituisce millisecondi. Passare uno dove serve l'altro è il bug JWT più diffuso in assoluto: un token che scade nel 1970, oppure che resta valido per i prossimi cinquantamila anni. Se un exp decodificato mostra una data nel passato remoto o in un futuro assurdo, hai trovato un fattore 1000.
L'altra sorpresa frequente è nbf, "not before". Un token può essere firmato perfettamente, non scaduto, e venire comunque rifiutato perché non è ancora valido: di solito è sintomo di orologi disallineati tra la macchina che emette e quella che valida, più che di qualcosa che non va nel token.
Il campo alg è un'istruzione, non una descrizione
L'header porta un claim "alg" che nomina l'algoritmo di firma, e la vulnerabilità JWT classica è una libreria che se ne fida. Se un validatore legge alg dal token e poi verifica di conseguenza, un attaccante può impostare alg a "none", togliere la firma ed entrare: è stato il token stesso a dire al validatore di non controllare.
L'attacco imparentato scambia RS256 con HS256. Con RS256 il token è firmato con una chiave privata e verificato con quella pubblica. Un validatore ingenuo che legge alg come HS256 userà quella chiave pubblica come segreto HMAC — e la chiave pubblica è, per definizione, pubblica. Entrambi gli attacchi sono vecchi e le librerie mantenute oggi rifiutano valori di alg che il chiamante non ha esplicitamente consentito. Se stai guardando un token il cui header dice "none", o stai testando qualcosa o stai guardando un attacco.
Cosa non mettere in un payload
Dato che il payload è leggibile da chiunque possieda il token, non è il posto per niente di privato. Nessuna nota interna sull'utente, nessuna logica di permessi che preferiresti non dover spiegare, nessun dato personale oltre a quello che serve al token per fare il suo lavoro. La firma impedisce la modifica, non la lettura: una distinzione che ha messo in imbarazzo parecchi team convinti che un token firmato fosse un token sigillato.
Domande frequenti
Il mio token viene inviato a un server?
No. Questo strumento è marcato "client": la separazione e la decodifica avvengono nella scheda del tuo browser e il token non lascia mai la macchina. Ma vale la pena mettere in discussione l'abitudine in generale: un JWT è una credenziale viva. Se hai incollato un token di produzione in un qualsiasi sito, questo incluso, l'ipotesi più prudente è che vada ruotato.
Posso controllare se questo token è valido?
Non qui, e su nessun sito che non gestisci tu — vedi la sezione sopra. Quello che puoi controllare a occhio è se il token è scaduto, dato che exp è lì nel payload decodificato. Copre il motivo più comune per cui un token smette di funzionare, senza che nessuna chiave cambi di mano.
Perché la scadenza mostra una data del 1970?
Perché un timestamp in millisecondi viene letto come se fosse in secondi. Dividi per 1000 e la data tornerà sensata. Qualunque cosa abbia prodotto il token sta usando Date.now() dove la RFC 7519 si aspetta Math.floor(Date.now() / 1000).
Posso modificare un token e rifirmarlo qui?
No. Cambiare un solo carattere del payload invalida la firma, e produrne una nuova valida richiede la chiave di firma — che, come detto sopra, non è roba da incollare in una pagina web. Modificare token è una cosa da fare nella tua suite di test con una chiave di test.
Il token ha i punti ma non si decodifica. Perché?
Spesso non è un JWT. I token cifrati (JWE) hanno cinque segmenti invece di tre, e il loro payload è davvero illeggibile senza la chiave. L'altra causa comune è il troncamento: i token sono lunghi e vengono tagliati dai formattatori di log, dalla larghezza del terminale, dalle celle dei fogli di calcolo. Se il segmento centrale finisce di colpo, probabilmente ti mancano dei caratteri invece di avere un token malformato.