JSON Web Token: from zero to hero #2
Secondo articolo della serie dedicata a JSON Web Token firmata zi0Black. Vantaggi e svantaggi legati alle Token Based Authentication.
JWT Strange Alg
Alcune librerie nel 2015 permettevano una funzionalità particolare di JWT senza fare i dovuti controlli. I token JWT nel loro standard prevedono l'algoritmo "none", questo significa che il token deve essere considerato valido a prescindere (perchè già validato). Il token, quindi, viene accettato senza verificare la firma e viene elaborato il payload.
Questa modalità non avrebbe nessun problema, se non fosse che le librerie accettavano come impostazione di default il valore "none" nel campo "alg" dell'header dei token. Per via di queste configurazioni di default era quindi possibile forgiare dei token con un payload arbitrario, ed era semplicemente sufficiente omettere la firma.
Header: {"alg": "HS256","typ": "JWT"}
Payload: {"sub": "1234567890","name": "guest","iat": 1516239022}
Sign: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header: {"alg": "none","typ": "JWT"}
Payload: {"sub": "1234567890","name": "admin","iat": 1516239022}
Sign:
RSA vs HMAC -> Key Confusion
Lo standard per i JWT prevede il supporto per algoritmi a chiave asimmetrica.
Con questi algoritmi, i token vengono firmati utilizzando una chiave privata, ma verificati utilizzando la chiave pubblica corrispondente. L'uso di algoritmi asimmetrici può risultare interessante in quanto, mantenendo la chiave privata per sé, è comunque possibile pubblicare quella pubblica per verificare che il token sia correttamente firmato.
La maggior parte delle librerie hanno una funzione simile a questa per verificare un token:
jwt.verify(token,verificationKey)
Nel caso si utilizzi un algoritmo asimmetrico (RSA) la chiave di verifica sarà la chiave pubblica, nel caso si in uso un algoritmo a chiave simmetrica (HMAC) allora sarà la stessa utilizzata per firmare il token.
Header: {"alg": "RS256","typ": "JWT"}
Payload: {"sub": "1234567890","name": "guest","iat": 1516239022}
Sign: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Come si può abusare di questo supporto per entrambi gli algoritmi? Se un server si aspetta un token firmato con RSA ma riceve un token firmato con HMAC, e come chiave per la firma viene usata quella pubblica, allora il server utilizzerà HMAC come algoritmo per verificare il token. Essendo che come parametro per "verificationKey" per la funzione "jwt.verify" viene utilizzata la chiave pubblica, risulterà che il token è correttamente firmato.
Header: {"alg": "HS256","typ": "JWT"}
Payload: {"sub": "1234567890","name": "admin","iat": 1516239022}
Sign: FFdrGxwH5YxeILO2QT4fwpMeJf36POk6yJVaadQssw6z
Con questa vulnerabilità è possibile quindi forgiare token arbitrari e creare una firma valida anche per il server, sfruttando la chiave pubblica e il fatto di avere il controllo sul campo "alg" dell'header.
Fine Seconda Parte
Con questo articolo abbiamo affrontato le prime due vulnerabilità di questa serie sui token JWT. Queste vulnerabilità sono causate dal fatto che un utente, a causa di una mancanza di controlli sul campo "alg" dell'header, può controllare in modo arbitrario quale algoritmo deve essere utilizzato per verificare la validità del token!
Se vuoi mettere in pratica ciò che hai appreso in questo articolo, ti consiglio la sottoscrizione a Pentester Lab Pro per accedere a moltissimi esercizi pratici su decine di vulnerabilità.
Tools
JOSEPH - by Dennis Detering
JavaScript Object Signing and Encryption Pentesting Helper (Burp Store)