it-swarm-eu.dev

JSON Web Tokens (JWT) come token di identificazione e autenticazione utente

Sto implementando un REST che richiede autenticazione. Non riesco a memorizzare alcuno stato per utente (come un token generato casualmente) perché il mio servizio non ha accesso diretto a un database, solo a un altro servizio di backend.

La soluzione che mi è venuta in mente è creare un token Web JSON ( JWT ) quando l'utente esegue l'autenticazione. Il set di attestazioni JWT contiene l'ID utente nel campo Oggetto ("sub"). Il server quindi crittografa direttamente le attestazioni impostate ("alg": "dir") utilizzando AES GCM con chiave a 256 bit ("enc": "A256GCM") creando un JWE . La chiave viene generata una volta all'avvio del servizio e memorizzata.

Per l'autenticazione, il client invia il nome utente/la password e il server risponde con il token sopra descritto. Il client invia quindi quel token con ogni richiesta successiva.

Quando il client invia il token con richieste successive, il server lo decodifica utilizzando la chiave e assume che l'ID utente nel campo "sub" sia l'ID dell'utente corrente, senza ulteriori controlli di autenticazione. La scadenza del token viene gestita dal campo "exp" nel set di attestazioni JWT.

La connessione tra il client e il server utilizzerà SSL/TLS, quindi il token non avrà perdite.

Sto usando questa libreria per creare e leggere JWT poiché non mi fido di me stesso per scrivere il codice di crittografia corretto.

Le mie domande:

  1. L'approccio sopra è sicuro? Un utente malintenzionato può impersonare un altro utente manipolando il token?
  2. L'approccio è troppo complicato? L'uso del MAC (in altre parole: JWS ) invece della crittografia avrebbe la stessa sicurezza? (o forse di più, poiché è più semplice e ci sono meno possibilità di fare un errore). Non c'è nulla di particolarmente segreto nel set di attestazioni JWT e l'utente che conosce il proprio ID non ha importanza.
  3. La mia scelta dell'algoritmo e della crittografia JWE è appropriata?
    • Per "alg" JWE, la libreria che sto usando supporta la crittografia diretta (utilizzando la chiave direttamente per crittografare il set di attestazioni) e RSA (generando una nuova chiave per crittografare il set di attestazioni per ciascun token e crittografando la chiave generata con un Chiave pubblica RSA). Ho scelto il primo perché è più semplice generare una chiave simmetrica rispetto a una chiave RSA.
    • Per JWE "enc", la libreria supporta AES GCM e AES CBC HMAC SHA2 (con varie lunghezze di bit). Ho scelto GCM arbitrariamente.
70
imgx64

L'approccio di base è valido: generare il JWT quando l'utente accede, aspettarsi che i messaggi successivi riportino il JWT, fidarsi del campo dell'oggetto nel JWT in quei messaggi successivi se il JWT è valido. Ma ci sono diverse cose che dovresti conoscere:

  1. Come dice Daisetsu, potresti usare un MAC ("alg": "HS256") in quanto i MAC sono specificamente progettati per prevenire l'alterazione del payload, mentre gli algoritmi di crittografia in genere (contro-intuitivamente) non lo sono. Tuttavia, poiché stai utilizzando AES specificamente in modalità GCM , ottieni già una crittografia a prova di manomissione ("crittografia autenticata"), quindi non è un problema.
  2. Quando convalidi un JWT in entrata, fai attenzione a ciò che ritieni valido. Ad esempio, potrei chiamare il tuo servizio con {"sub": "me", "alg": "none"} e sebbene JWT sia valido in un certo senso, non è qualcosa che vuoi accettare.
  3. Poiché JWT è una bozza, non ancora uno standard, potrebbe cambiare. Se cambia abbastanza, la libreria che stai utilizzando potrebbe dover cambiare in modo da interrompere la compatibilità con il tuo codice.
  4. Se non è possibile memorizzare alcuno stato sul lato server, non è possibile invalidare JWT quando l'utente si disconnette. In effetti il ​​tuo servizio non ha alcuna funzione di disconnessione, il che potrebbe rappresentare un problema di sicurezza, soprattutto se in futuro il tempo di scadenza viene impostato troppo.
  5. Se si imposta l'ora di scadenza troppo presto, è possibile che si sia verificato un problema con gli utenti che hanno ancora effettuato l'accesso ma non dispongono di un JWT valido. Ciò può portare a problemi di gestione degli errori e di flusso di lavoro dell'utente.

Dato che hai detto che il tuo server non ha accesso a un database, presumo che il login effettivo sia gestito da qualche altra parte, forse il server back-end che hai citato. Non hai detto come il tuo server sa che l'utente ha appena effettuato l'accesso. A seconda della percezione da parte dell'utente della relazione tra il tuo servizio e la cosa che sa di aver effettuato l'accesso, gli ultimi due punti sopra potrebbero essere discutibili.

52
gatkin

Se nessuno dei dati è sensibile, è sufficiente preservare l'integrità dei dati. La firma (JWS) del token dovrebbe essere sufficiente per farlo.

Se stai solo facendo una firma, dovresti andare bene con HMAC SHA-256. Ricordare di impostare una scadenza del token e di verificare se l'utente si è disconnesso manualmente (in tal caso, invalidare il token). Una volta che prendi in considerazione la scadenza e il logout, non c'è molto di cui preoccuparsi (per quanto riguarda l'algoritmo). Le probabilità che qualcuno rompa un SHA-256 nel tempo di una singola sessione (dovrebbe) sono relativamente basse (supponendo che tu debba richiedere nuovamente l'autorizzazione ad un intervallo RAGIONABILE).

Come sempre con la firma, assicurati di fornire il contenuto da firmare (nome utente, tipo di account, ecc.), Non lasciare mai firmare nessuno dei dati definiti dall'utente o potresti trovarti in una situazione pericolosa.

Disclaimer: questo post è rigorosamente la mia opinione. Non sto dichiarando l'affidabilità o l'idoneità delle mie risposte. Consultare sempre un professionista della sicurezza per discutere dei problemi specifici relativi all'implementazione della sicurezza. Questo è puramente educativo.

10
Daisetsu