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

70

Sto implementando un servizio REST che richiede l'autenticazione. Non riesco a memorizzare nessuno stato per utente (come un token generato casualmente) perché il mio servizio non ha accesso diretto a un database, ma solo a un altro servizio di back-end.

La soluzione che mi è venuta in mente è la creazione di un token Web JSON ( JWT ) quando l'utente si autentica. Il set di attestazioni JWT contiene l'ID utente nel campo Oggetto ("sub"). Il server quindi crittografa il set di attestazioni direttamente ("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 in memoria.

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

Quando il client invia il token con richieste successive, il server lo decripta usando 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 perderà.

Sto usando questa libreria per creare e leggere i JWT perché non mi fido di scrivere 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'utilizzo del MAC (in altre parole: JWS ) al posto della crittografia ha la stessa sicurezza? (o forse di più, dal momento che è più semplice e c'è meno possibilità di commettere un errore). Non c'è nulla di particolarmente segreto nel set di attestazioni di JWT e l'utente che conosce il proprio ID non ha importanza.
  3. La scelta dell'algoritmo e della crittografia JWE è appropriata?
    • Per JWE "alg", la libreria che sto utilizzando 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 il generato chiave con una 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.
posta imgx64 11.02.2014 - 11:33
fonte

2 risposte

50

Il tuo approccio di base è valido: genera il JWT quando l'utente esegue il login, si aspetta che i successivi messaggi trasportino il JWT, si fidi del campo soggetto nel JWT in quei messaggi successivi se il JWT è valido. Ma ci sono molte cose da sapere:

  1. Come dice Daisetsu, è possibile utilizzare un MAC ("alg": "HS256") poiché i MAC sono specificamente progettati per impedire l'alterazione del payload, mentre gli algoritmi di crittografia tipicamente (contro-intuitivamente) sono non. Tuttavia, poiché stai utilizzando in modo specifico AES nella modalità GCM , ottieni già la crittografia resistente alle manomissioni ("crittografia autenticata"), quindi non è un problema.
  2. Quando convalida un JWT in entrata, fai attenzione a ciò che consideri valido. Ad esempio, potrei chiamare il tuo servizio con {"sub": "me", "alg": "none"} e mentre quel JWT è 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 compromettere la compatibilità con il tuo codice.
  4. Se non è possibile memorizzare alcun stato lato server, non è possibile invalidare il JWT quando l'utente si disconnette. In effetti il tuo servizio non ha alcuna funzione di disconnessione, il che potrebbe essere un problema di sicurezza, specialmente se in futuro si imposta un limite di scadenza troppo lungo.
  5. Se imposti l'ora di scadenza troppo presto, potresti avere un problema con gli utenti che stanno ancora effettuando l'accesso ma che non hanno un JWT valido. Ciò potrebbe causare problemi di gestione degli errori e problemi del flusso di lavoro degli utenti.

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 di backend che hai menzionato. Non hai detto come il tuo server sa che l'utente ha appena effettuato l'accesso. A seconda della percezione dell'utente della relazione tra il tuo servizio e la cosa che sanno di aver effettuato l'accesso, gli ultimi due punti sopra potrebbero essere discutibili.

    
risposta data 12.02.2014 - 12:59
fonte
9

Se nessuno dei dati è sensibile, tutto ciò che devi fare è preservare l'integrità dei dati. Signing (JWS) il token dovrebbe essere sufficiente per farlo.

Se stai solo facendo una firma dovresti stare bene con HMAC SHA-256. Ricordarsi di impostare una scadenza del token e di verificare se l'utente si è disconnesso manualmente (in tal caso, invalidare il token). Una volta presa in considerazione la scadenza e il logout, non c'è molto di cui preoccuparsi (algoritmo saggio). Le probabilità di qualcuno che cracka un SHA-256 nel tempo di una singola sessione (dovrebbe) essere relativamente bassa (presupponendo che tu richieda la re-auth ad un intervallo RAGIONEVOLE).

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

Disclaimer: Questo post è strettamente la mia opinione. Non sto affermando nulla sull'affidabilità o idoneità delle mie risposte. Dovresti sempre consultare un professionista della sicurezza per discutere i tuoi specifici problemi di implementazione della sicurezza. Questo è puramente educativo.

    
risposta data 11.02.2014 - 22:48
fonte

Leggi altre domande sui tag