Verificare la firma di un JSON Web Token (JWT)

verifica la firma di un JWT (HS256, HS384, HS512, RS256, RS384, RS512) a partire da un segreto o da una chiave pubblica, e ispeziona i suoi claim
Per HS256 / HS384 / HS512: la stringa segreta. Per RS256 / RS384 / RS512: la chiave pubblica in formato PEM.

Perché verificare la firma di un JWT?

Un JSON Web Token (JWT) si scompone in tre parti separate da punti: header.payload.signature. Decodificare un JWT consiste semplicemente nel leggere le prime due parti (che sono Base64URL). Chiunque può farlo, e chiunque può fabbricare un JWT con il payload di sua scelta. Ciò che rende un JWT degno di fiducia è solo la firma: senza verifica, accettare un JWT significa lasciar entrare a casa vostra ogni persona che pretende di essere qualcuno, senza chiedere un documento di identità.

Questo strumento verifica la firma di un JWT a partire da una chiave. Non si limita a decodificare: ricalcola la firma a partire da header, payload e la vostra chiave, poi la confronta con la firma del token. Se le due concordano, il token è autentico. Altrimenti, è stato forgiato, modificato, o firmato con un'altra chiave.

La verifica è la pietra angolare di qualsiasi architettura che usi JWT per l'autenticazione o l'autorizzazione: senza firma valida, il payload può mentire. Un attaccante che modificasse "role":"user" in "role":"admin" non avrebbe alcuna difficoltà a farlo se il server verificasse solo il formato del token e non la sua firma.

Algoritmi comuni

La specifica JWT (RFC 7518, JSON Web Algorithms) definisce diverse famiglie di algoritmi. Ecco le più usate in produzione:

  • HMAC (HS256, HS384, HS512): firma simmetrica basata su HMAC-SHA. La stessa chiave segreta serve a firmare e a verificare. Semplice da mettere in atto, performante, ma ogni parte capace di verificare il token è anche capace di emetterlo. Adatto agli scenari in cui emettitore e verificatore sono lo stesso team o lo stesso servizio.
  • RSA (RS256, RS384, RS512): firma asimmetrica. La chiave privata firma, la chiave pubblica verifica. Ideale quando emettitore e verificatori sono entità distinte (OAuth2, OpenID Connect, federazione di identità). È l'algoritmo privilegiato dalla maggior parte dei provider di identità pubblici.
  • ECDSA (ES256, ES384): firma asimmetrica su curve ellittiche. Stessa logica di RSA (chiave privata per firmare, chiave pubblica per verificare) ma con chiavi e firme più compatte per un livello di sicurezza equivalente. Sempre più diffuso nelle architetture moderne.

Come fornire la chiave

Il formato della chiave atteso dipende dall'algoritmo dichiarato nell'header del JWT:

  • HS256, HS384, HS512: la chiave è una stringa segreta (string). È il secret condiviso con l'emettitore, spesso memorizzato in una variabile d'ambiente come JWT_SECRET. Nessuna formattazione particolare, solo il valore grezzo.
  • RS256, RS384, RS512: la chiave è una chiave pubblica RSA nel formato PEM, che inizia con -----BEGIN PUBLIC KEY----- e termina con -----END PUBLIC KEY-----. Conservate i ritorni a capo così come sono, altrimenti OpenSSL rifiuta di farne il parsing.
  • ES256, ES384: la chiave è una chiave pubblica ECDSA nel formato PEM, sulla curva corrispondente (P-256 per ES256, P-384 per ES384).

Esempio di chiave pubblica RSA attesa

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxe...
...vQIDAQAB
-----END PUBLIC KEY-----

Come funziona la verifica?

Il nostro server riproduce esattamente l'operazione che ha fatto l'emettitore:

  1. Separa il JWT in header, payload e firma.
  2. Concatena base64url(header) + "." + base64url(payload).
  3. Per HMAC, calcola un HMAC-SHA-256/384/512 con la vostra chiave segreta, poi confronta con la firma ricevuta tramite hash_equals (confronto a tempo costante per evitare attacchi temporali).
  4. Per RSA, chiama openssl_verify con la vostra chiave pubblica nel formato PEM.

Casi d'uso

  • Debug di autenticazione API: ricevete un 401, verificate se il vostro token è effettivamente firmato con la chiave attesa.
  • Validazione di un token ricevuto da un provider: un partner (Auth0, Keycloak, Cognito, Okta) vi invia JWT firmati in RS256; volete confermare che provengano effettivamente da lui con la sua chiave pubblica.
  • Audit di sicurezza: verificare che un servizio terzo firmi correttamente i suoi token con un algoritmo robusto, e non in HS256 con un secret debole.
  • Test manuali: verificare che un JWT generato dal vostro codice passi la verifica con la chiave pubblica fornita.
  • Verifica rapida di un token ricevuto: durante l'integrazione di un SSO o di un'API partner, verificare in pochi secondi che la catena firma/chiave funzioni prima di scrivere una riga di codice.

Come usare lo strumento

  1. Incollate il JWT completo (le tre parti separate da punti).
  2. Indicate la chiave adatta all'algoritmo dell'header:
    • Per HS256, HS384 o HS512, la chiave è la stringa segreta condivisa con l'emettitore. È una stringa libera, spesso memorizzata in una variabile d'ambiente come JWT_SECRET.
    • Per RS256, RS384 o RS512, la chiave è la chiave pubblica nel formato PEM, che inizia con -----BEGIN PUBLIC KEY----- e termina con -----END PUBLIC KEY-----.
  3. Avviate la verifica. Lo strumento mostra lo stato (valido o invalido) e il payload decodificato.

Trappole comuni da evitare

  • Algoritmo "none": la spec autorizza alg: none, che significa "nessuna firma". Una falla classica consiste nel fabbricare un token con questo header sperando che il server lo accetti. Il nostro strumento rifiuta sistematicamente i token con alg: none.
  • Confusione HMAC vs RSA (algorithm confusion): un attaccante cambia l'algoritmo RS256 in HS256 e firma il payload con la chiave pubblica RSA usata come secret HMAC. Se il server non controlla l'algoritmo, accetta il token. Bloccate sempre l'algoritmo atteso lato server.
  • Secret HMAC hardcoded nel codice: un secret committato in un repository Git rende caduca tutta la fiducia dei token. Memorizzate i secret in variabili d'ambiente o in un vault applicativo.
  • Chiave pubblica vs chiave privata: per verificare un JWT firmato in RSA o ECDSA, si fornisce la chiave pubblica, mai la privata. La privata serve solo a firmare e non deve mai uscire dall'emettitore.
  • Scadenza ignorata: una firma valida su un token scaduto non deve mai essere accettata. Pensate a verificare exp e nbf.
  • Audience non controllata: un token destinato all'API A non dovrebbe essere accettato dall'API B. Verificate il claim aud.

Claim temporali: exp e nbf

Oltre alla firma, un JWT valido deve anche rispettare i suoi vincoli temporali:

  • exp (expiration): il token non è più valido dopo questa data.
  • nbf (not before): il token non è ancora valido prima di questa data.

Il nostro strumento segnala esplicitamente quando un token è scaduto o non ancora valido, anche se la sua firma è corretta. È importante: una firma valida su un token scaduto non deve mai essere accettata in produzione.

Differenza con il nostro JWT decoder

Il nostro JWT decoder si limita a decodificare le parti header e payload per renderle leggibili. Non effettua alcuna verifica di firma e non chiede chiave. Usatelo per ispezionare rapidamente il contenuto di un token. Usate il JWT verifier (questa pagina) non appena avete bisogno di provare che un token sia autentico. Per fabbricare un JWT firmato a fini di test, usate il nostro JWT builder.

Domande frequenti

Perché RS256 piuttosto che HS256?

Con HS256, emettitore e verificatore condividono lo stesso secret: ogni verificatore può quindi emettere token. È gestibile quando si controllano entrambi i lati. Non appena si parla di un provider di identità unico con più servizi consumatori, si passa a RS256: l'emettitore conserva la chiave privata, si distribuisce la chiave pubblica a tutte le API che devono verificare. Nessuna API consumatrice può allora forgiare token.

Come recuperare la chiave pubblica di un provider di identità (IdP)?

La maggior parte degli IdP espone un endpoint JWKS standardizzato (per esempio https://esempio.com/.well-known/jwks.json). Questo endpoint restituisce un JSON contenente le chiavi pubbliche attive. Potete convertire la voce JWK che corrisponde al kid dell'header del vostro JWT in chiave PEM tramite il comando openssl o tramite una libreria JWKS del vostro stack (per esempio jose-jwt, jwks-rsa).

Cosa fare se la verify fallisce?

Verificate prima l'algoritmo: un token firmato in HS256 non si verifica con una chiave RSA, e viceversa. Verificate poi la chiave: un carattere bianco in più, un ritorno a capo mancante in una chiave PEM, o un secret HMAC leggermente diverso da quello usato dall'emettitore bastano a far fallire la verifica. Se l'IdP ha effettuato una rotazione di chiave, il vostro kid può puntare a una chiave che non avete più.

Cos'è JWKS?

JWKS (JSON Web Key Set, RFC 7517) è un formato JSON che descrive un insieme di chiavi pubbliche. Ogni chiave è identificata da un kid (key ID) e il JWT da verificare riferisce questo kid nel suo header. Il meccanismo permette all'IdP di ruotare le sue chiavi senza rompere i verificatori: interrogano semplicemente l'endpoint JWKS per recuperare la chiave corrispondente al kid del token ricevuto.

Come generare una coppia di chiavi RSA per firmare i miei JWT?

Con OpenSSL: openssl genrsa -out private.pem 2048 poi openssl rsa -in private.pem -pubout -out public.pem. La chiave privata firma lato emettitore, la chiave pubblica verifica lato consumatore. Per nuovi servizi, preferite 3072 o 4096 bit.

Bisogna cifrare il JWT oltre a firmarlo (JWE)?

Un JWT firmato (JWS) garantisce integrità e autenticità, ma il payload resta leggibile da chiunque lo recuperi. Se il token contiene dati sensibili (identificatori interni, diritti dettagliati, dati personali), considerate il formato JWE (JSON Web Encryption) che cifra il payload oltre a firmarlo.

Esempio di richiesta

curl -X POST https://cdrn.fr/api/v1/tools/jwt-verifier/execute \
  -H "Content-Type: application/json" \
  -d '{"token":"...","key":"..."}'

Schema di input

Campo Tipo Richiesto Predefinito
token text
key text

Endpoint

  • GET https://cdrn.fr/api/v1/tools - elenca tutti gli strumenti disponibili
  • GET https://cdrn.fr/api/v1/tools/jwt-verifier - recupera lo schema di questo strumento
  • POST https://cdrn.fr/api/v1/tools/jwt-verifier/execute - esegue questo strumento con un payload JSON