JWT (JSON Web Token)

Indice dei contenuti

    Un JWT (JSON Web Token, RFC 7519) è un token compatto e URL-safe che rappresenta un insieme di claims — affermazioni su un’entità, tipicamente un utente — come oggetto JSON firmato (o cifrato). È lo standard de facto per l’autenticazione stateless nelle API REST e nelle Single Page Application: il server non mantiene sessioni in memoria, ma emette un token firmato che il client presenta ad ogni richiesta successiva. Il server verifica la firma e riconosce il portatore senza consultare un database di sessioni.

    Struttura

    Un JWT è composto da tre parti codificate in Base64URL separate da punti:

    header.payload.signature

    Header: oggetto JSON che specifica il tipo di token (typ: "JWT") e l’algoritmo di firma (alg).

    { "alg": "RS256", "typ": "JWT" }

    Payload: oggetto JSON con i claims. I claims registrati (standard) includono iss (issuer), sub (subject, tipicamente l’ID utente), exp (expiration time), iat (issued at), aud (audience). Si aggiungono claims custom (es. role, email).

    { "sub": "1234567890", "role": "admin", "exp": 1893456000 }

    Signature: firma crittografica di Base64URL(header) + "." + Base64URL(payload), calcolata con la chiave privata del server (RS256) o con un segreto condiviso (HS256).

    Algoritmi di firma

    La scelta dell’algoritmo è critica:

    AlgoritmoTipoNote
    HS256HMAC-SHA256, simmetricoUn solo segreto condiviso tra emittente e verificatore. Problematico se più servizi verificano il token.
    RS256RSA-SHA256, asimmetricoIl server firma con la chiave privata; i client verificano con la chiave pubblica. Più scalabile.
    ES256ECDSA-SHA256, asimmetricoCome RS256 ma più efficiente. Raccomandato per nuovi sistemi.
    noneNessuna firmaMai usare in produzione.

    Vulnerabilità principali

    Algorithm confusion (alg: none): alcune implementazioni naive accettano token con "alg": "none" — nessuna firma richiesta. Un attaccante può costruire un token arbitrario modificando il payload. Verificare sempre che l’algoritmo corrisponda a quello atteso, indipendentemente da quanto dichiarato nell’header.

    RS256 → HS256 confusion: se il server usa RS256 e la sua chiave pubblica è nota (spesso lo è), un attaccante può firmare un token con HS256 usando la chiave pubblica RSA come segreto HMAC. Se la libreria di verifica non è esplicitamente configurata per accettare solo RS256, lo accetta come valido. Impostare sempre l’algoritmo atteso lato server, non fidarsi dell’header.

    exp non verificato: alcune implementazioni dimenticano di verificare la scadenza del token. Un token scaduto non dovrebbe mai essere accettato.

    Payload non cifrato: il payload è codificato in Base64URL, non cifrato — chiunque intercetti il token può decodificarne il contenuto. Non inserire dati sensibili (password, numeri di carta) nel payload. Se la riservatezza è necessaria, usare JWE (JSON Web Encryption).

    Secret debole in HS256: se il segreto HMAC è breve o prevedibile, è attaccabile offline per forza bruta (tool: hashcat con modalità JWT).

    JWT stateless vs. revoca

    Il vantaggio principale del JWT — non richiedere stato lato server — è anche il suo limite principale: un JWT valido non può essere invalidato prima della scadenza senza introdurre uno stato server (blocklist). Se un utente fa logout o le sue credenziali vengono compromesse, il token rimane valido fino a exp. Le strategie comuni sono:

    • Usare token con scadenza breve (15–60 minuti) + refresh token con scadenza lunga
    • Mantenere una blocklist lato server per i token revocati (riducendo il beneficio dello stateless)
    • Ruotare il segreto/chiave di firma (invalida tutti i token in circolazione)

    Ultimo aggiornamento: