Cosa dimostra un JWT decodificato
Un decodificatore JWT ti mostra cosa afferma un token. Non può mostrarti se tali affermazioni sono vere. Questa guida copre cosa sono i tre segmenti, cosa stabilisce e cosa non stabilisce la decodificazione e gli attacchi che vivono nello spazio tra i due.
Tre segmenti, due dei quali sono solo JSON
Un JWT nella sua forma comune è un JWS: tre segmenti base64url separati da punti. Il primo è un'intestazione, il secondo un payload, il terzo una firma.
L'intestazione e il payload sono normali oggetti JSON codificati in base64url. Codificato, non crittografato. Chiunque abbia il token può leggerli entrambi, istantaneamente, senza chiave: non è un difetto, è il design. Una JWT è una dichiarazione firmata, non una busta sigillata. La firma garantisce che la dichiarazione non è stata alterata; non fa nulla per mantenerlo privato.
Vale la pena affermare chiaramente la conseguenza perché viene regolarmente trascurata: non inserire mai nulla di confidenziale in un payload JWT. Non una password, non un identificatore nazionale completo, non i dettagli interni del sistema. Supponiamo che il payload sia pubblico, perché per chiunque abbia il token lo è.
Il terzo segmento è la firma, calcolata sui primi due. È l'unica parte che ha un valore di sicurezza ed è la parte che un decodificatore non può valutare.
Cosa dimostra la decodificazione: niente
Questo è il punto di tutta la guida. La decodifica di un JWT analizza due stringhe base64url in JSON. Conferma che il token è ben formato. Non conferma che il token sia autentico, che sia stato emesso dalla parte menzionata nella dichiarazione "iss", che le dichiarazioni non siano state modificate o che sia mai stato valido.
Chiunque può costruire un token. Prendi qualsiasi JWT, cambia "role": "user" in "role": "admin", ricodifica il payload, pinza qualsiasi firma alla fine e un decodificatore visualizzerà le tue affermazioni modificate esattamente con la stessa sicurezza con cui mostrava l'originale. Non ha modo di conoscere la differenza, perché verificare la differenza è un'operazione diversa che richiede una chiave che il decoder non possiede.
Quindi, quando un decodificatore, questo o qualsiasi altro, ti mostra "exp: 2026-01-01", ciò che ti sta realmente dicendo è: questo token contiene un'affermazione che scade in quella data. Il significato di tale affermazione dipende interamente dalla validità della firma, che non è stata verificata.
Questo strumento si limita a decodificarli e lo dice ogni volta sulla pagina, accanto ai risultati. Non in una nota a piè di pagina. Il motivo è che un decodificatore che non parla di questo sta addestrando i suoi utenti a leggere dati non verificati come se fossero verificati, e questa abitudine è la radice di un'intera famiglia di bug di autenticazione.
Perché questo strumento non offre la verifica
La verifica richiede tre cose che una pagina web non può avere responsabilmente: la chiave dell’emittente, l’algoritmo fissato in anticipo e una politica su cosa rifiutare.
La chiave è il problema ovvio. Per gli algoritmi HMAC (HS256 e amici) la chiave è un segreto condiviso, lo stesso segreto utilizzato per creare token. Incollarlo in una pagina Web significa incollare una credenziale in grado di coniare token validi in una pagina Web. Per RSA e ECDSA la chiave pubblica non è segreta, ma dovresti comunque recuperare quella giusta dall'endpoint JWKS giusto e fidarti di ciò che avevi.
L’algoritmo è il problema sottile e la fonte di due attacchi ben noti. Il primo è alg: "none": l'intestazione afferma che il token non è firmato e un verificatore che rispetta l'intestazione anziché la propria configurazione accetta qualsiasi cosa. Il secondo è la confusione da RS256-a-HS256: l'aggressore prende una chiave pubblica, che è, per definizione, pubblica, modifica l'intestazione in HS256 e firma il token utilizzando quella chiave pubblica come segreto HMAC. Un verificatore che legge l'algoritmo dal token e cerca "la chiave" lo convaliderà.
Entrambi gli attacchi derivano dallo stesso errore: lasciare che il token dica al verificatore come controllarlo. Un verificatore corretto ignora l'algoritmo dell'intestazione e utilizza quello con cui è stato configurato. Questa è una decisione che appartiene al sistema che si fida del token, non a uno strumento di comodità e non a chiunque abbia incollato qualcosa in un modulo.
Perché non incollare i token di produzione ovunque
Un token di accesso è una credenziale al portatore. Questo è ciò che significa "portatore" nell'intestazione Autorizzazione: chiunque lo porti, sei tu. Non esiste un secondo fattore e di solito non c'è modo di distinguere un token rubato da uno legittimo. Fino alla scadenza, è una chiave funzionante per il tuo account.
Quindi incollare un token live in qualsiasi pagina web significa trasmettere una credenziale a quella pagina. Questo decodifica tutto localmente e non effettua richieste di rete dopo il caricamento della pagina: puoi confermarlo nel pannello di rete del tuo browser, e dovresti, perché impiega dieci secondi. Ma notate qual è in realtà questo argomento: un’affermazione, su un sito web, secondo cui il sito web è affidabile. Ogni sito che esfiltra token fa esattamente la stessa affermazione e un visitatore non può notare la differenza a colpo d'occhio.
L'abitudine sicura non dipende dal giudizio corretto dei siti. Utilizza token scaduti, token dell'ambiente di test o token che hai coniato per lo scopo. Se hai già incollato un token di produzione da qualche parte, ovunque, ruotalo. La revoca è economica; un incidente non lo è.
Lo stesso vale con maggiore forza per la firma delle chiavi. Non esiste alcun motivo legittimo per digitare un segreto HMAC o una chiave privata in una pagina Web e qualsiasi sito che ne richiede uno per "verificare" il token richiede la possibilità di falsificare token. Questo è il motivo concreto per cui questo strumento non ha funzionalità di verifica: la funzionalità richiede la richiesta.
Leggere le affermazioni che contano
RFC 7519 registra un piccolo set di nomi di attestazioni. "iss" è l'emittente, "sub" l'oggetto di cui tratta il token, "aud" il pubblico previsto, "exp" la scadenza, "nbf" la prima ora valida, "iat" l'ora di emissione e "jti" un ID univoco per il rilevamento della riproduzione. Tutto il resto è specifico dell'applicazione.
Le dichiarazioni temporali sono valori NumericDate: secondi dall'epoca di Unix, non millisecondi. Questo fa inciampare costantemente le persone, perché la maggior parte dei valori temporali di JavaScript sono millisecondi. A un token che sembra scadere tra 1970 viene solitamente assegnato un valore in millisecondi; uno che sembra scadere nell'anno 55000 di solito ha un secondo valore moltiplicato per 1000 da qualche parte.
"aud" merita particolare attenzione durante il debug. Un token perfettamente valido può comunque essere sbagliato, perché è stato emesso per un pubblico diverso. Un verificatore che controlla la firma ma non il pubblico accetterà un token coniato interamente per un altro servizio, il che è un vero percorso di escalation dei privilegi nei sistemi che condividono un provider di identità.
Questo strumento esegue il rendering delle dichiarazioni temporali in UTC, contrassegna un token scaduto come scaduto e lo associa a un promemoria che la dichiarazione di scadenza significa qualcosa solo se la firma è valida. Il promemoria c'è perché "dice che non è scaduto" è il momento esatto in cui l'abitudine ai dati non verificati fa il suo danno.
Una breve lista di controllo per il sistema che si fida
Se stai scrivendo il codice che accetta i token anziché semplicemente ispezionarne uno, quella che segue è la versione breve di ciò che fa un verificatore corretto.
- Verifica innanzitutto la firma, con una chiave ottenuta fuori banda, prima di leggere qualsiasi reclamo.
- Blocca l'algoritmo nella tua configurazione. Non leggerlo mai dall'intestazione del token. Rifiuta "nessuno" incondizionatamente.
- Controlla "exp" e "nbf" rispetto a un orologio attendibile, con al massimo una piccola tolleranza per lo skew.
- Confronta "iss" e "aud" con i valori attesi. Una firma valida su un token destinato a qualcun altro è ancora il token sbagliato.
- Utilizza una libreria controllata per la tua piattaforma anziché assemblarla tu stesso. Ogni elemento di questo elenco è presente perché le implementazioni hanno sbagliato.
- Mantieni breve la durata dei token e stabilisci un percorso di revoca. I token di breve durata limitano il danno della perdita che non hai ancora notato.
Cosa succede a ciò che incolli
- Ogni conversione, hash, decodifica e differenza viene eseguita nella scheda del tuo browser. Nessun input viene caricato, registrato o archiviato su un server, perché non è coinvolto alcun server una volta caricata la pagina.
- Gli hash provengono dall'implementazione Web Crypto del browser e gli UUID dal suo generatore casuale crittograficamente sicuro. Nessuno dei due prevede una chiamata di rete.
- Niente di ciò che digiti viene scritto nella memoria locale o in un cookie. Ricaricando la pagina la si elimina; chiudendo la scheda la si elimina.
- L'analisi a livello di sito viene eseguita solo sull'host di produzione canonico configurato e viene divulgata nell'Informativa sulla privacy; gli host locali e di anteprima lo rifiutano. Valori, token, URL e contenuti dei file incollati sono esclusi dagli eventi di analisi di ToolAcre. La pubblicità è disabilitata nella configurazione attuale.
- Detto questo: una chiave JWT o API è una credenziale attiva. L'abitudine più sicura è non incollarne mai uno in una pagina web che non hai scritto tu, per quanto attendibili siano le sue affermazioni, inclusa questa.
Domande
Questo strumento verifica la firma?
No, e non lo farà mai. Decodifica l'intestazione e il payload e mostra cosa contengono. Non controlla la firma, quindi nulla di ciò che mostra dimostra che il token è autentico, inalterato o emesso da chiunque nomina.
Allora come faccio a sapere che un token è autentico?
Verificando la firma con la chiave dell'emittente, utilizzando una libreria controllata, con l'algoritmo bloccato nella tua configurazione anziché letto dal token. Questo è lavoro per il servizio che si fida del token, in un ambiente che detiene legittimamente la chiave.
Il mio token viene inviato da qualche parte quando lo decodifico qui?
No. La decodifica avviene nella scheda del tuo browser utilizzando il JavaScript della pagina e la pagina non effettua richieste di rete dopo il caricamento. Puoi verificarlo nel pannello di rete del tuo browser. Non dovresti comunque incollare i token di produzione negli strumenti web per una questione di abitudine, perché quell'abitudine deve funzionare su siti che non sono onesti al riguardo.
Perché chiunque può leggere il mio payload JWT?
Perché il payload è codificato base64url, non crittografato. Una JWS è una dichiarazione firmata, non sigillata. Se hai bisogno che i contenuti siano illeggibili hai bisogno di JWE, il formato del token crittografato - e quindi un decodificatore non può mostrarti nulla senza la chiave.
Cos'è alg: "nessuno"?
Un valore di intestazione che dichiara che il token non è firmato. Esiste nelle specifiche per contesti in cui l'integrità è garantita con altri mezzi, ed è una trappola permanente: un verificatore che si fida dell'algoritmo dell'intestazione accetterà qualsiasi token che dichiara "nessuno". Questo strumento lo segnala ogni volta che appare.
Il mio token ha cinque segmenti e non verrà decodificato. Perché?
Cinque segmenti indicano un JWE, un token crittografato, anziché un JWS firmato. Il suo contenuto non può essere letto senza la chiave di decrittazione, quindi non c'è davvero nulla da mostrare per un decodificatore. Questo strumento identifica esplicitamente il caso invece di segnalare un vago errore di analisi.
La scadenza sembra errata di un fattore pari a 1000.
Le dichiarazioni temporali di JWT sono NumericDate: secondi dall'epoca, non millisecondi. Un valore prodotto da Date.now() è mille volte troppo grande. L'utilità timestamp in questo toolkit converte tra i due e ti dice sempre quale unità ha utilizzato.
È sicuro archiviare un JWT in localStorage?
È un compromesso, non un sì o un no. localStorage è leggibile da qualsiasi JavaScript in esecuzione sulla tua origine, quindi una singola vulnerabilità XSS esfiltra il token. Un cookie httpOnly non è leggibile da JavaScript ma necessita di protezione CSRF. La sintesi onesta è che nessuno dei due è gratuito e la decisione dipende dal modello di minaccia della tua applicazione.
Limitazioni
- Questo strumento decodifica solo. Non verifica le firme e questa è una decisione di progettazione permanente piuttosto che una caratteristica mancante: consulta la guida sopra per il motivo.
- I token crittografati (JWE, cinque segmenti) non possono essere decodificati senza la chiave. Lo strumento li identifica e si ferma.
- I JWT nidificati, ovvero un token il cui payload è esso stesso un token, non vengono scartati automaticamente. Decodifica il token interno come passaggio separato.
- I significati delle attestazioni oltre il set registrato definito in RFC 7519 sono specifici dell'applicazione, quindi lo strumento ne mostra i valori senza interpretarli.
- Una scadenza mostrata qui riflette solo ciò che il token afferma su se stesso. Il significato di tale affermazione dipende da una firma che questo strumento non controlla.
- I token più grandi di 200,000 caratteri vengono rifiutati. Qualsiasi JWT reale è più piccolo di ordini di grandezza.