Utilizzo sicuro di JWT con protezione CSRF e token di aggiornamento

8

Sto implementando i JWT nella mia app e mi piacerebbe renderli il più sicuri possibile. Preparerò tutto ciò che sto pianificando, apprezzerei molto qualsiasi suggerimento sulla sicurezza di questa implementazione. Questo è il mio sito, ho pieno accesso ad ogni aspetto di esso, sia front-end che back-end.

Questa sarà una SPA, utilizzando un'API per accedere al back-end. Sto usando JWT per salvare le chiamate DB con ogni hit dell'API.

JWTs

Le JWT sono memorizzate in un cookie access_token . Vengono prima firmati e poi crittografati utilizzando jose-jwt . L'algoritmo di firma è HS256, la crittografia è DIR. Includono l'ID dell'utente, una richiesta di scadenza exp e diverse altre attestazioni personalizzate. Le JWT scadono tra 30 minuti e il cookie JWT scade tra 7 giorni.

(versione breve):

  • JWT memorizzato nel cookie
  • JWT include l'ID utente
  • JWT firmato e quindi crittografato
  • JWT exp reclamo impostato su 30 minuti in futuro
  • Il cookie JWT ha una scadenza di 7 giorni in futuro

Protezione CSRF

Le JWT includono una dichiarazione cst che memorizza un token CSRF generato in modo casuale. Il token CSRF viene inviato nel corpo della risposta al momento dell'accesso e quando viene emesso un nuovo JWT. Il token CSRF è memorizzato nel localStorage del browser. Viene inviato con ogni richiesta e convalidato rispetto al valore nel JWT.

(versione breve):

  • JWT include un token CSRF generato a caso
  • Token CSRF inviato al momento dell'accesso e archiviato in localStorage
  • Token CSRF inviato nell'intestazione della richiesta di tutte le richieste
  • Token CSRF dell'intestazione rispetto al token CSRF nel JWT

Token di aggiornamento

Poiché i JWT scadono tra 30 minuti, è necessario aggiornarli. Il JWT include un'affermazione rfs che memorizza un token di aggiornamento casuale. Questo token di aggiornamento viene anche memorizzato nel DB (una tabella separata dagli utenti per consentire più sessioni). Se il JWT è scaduto (in base alla sua rivendicazione exp ), il DB viene controllato per garantire che l'utente sia ancora valido (ad esempio, account non cancellato, password non modificata, ecc.). Se l'utente è valido, il token di aggiornamento viene verificato e un nuovo token JWT / CSRF viene generato e restituito nella risposta. Se l'utente non è valido, il access_token viene rinviato con un valore arbitrario come 0 e la sua scadenza viene impostata sul passato in modo che il browser la cancelli. Il token CSRF viene passato vuoto, quindi verrà cancellato da localStorage. Tutti i token di aggiornamento per l'utente vengono cancellati dal DB.

(versione breve):

  • Se JWT è scaduto, controlla il DB utente per verificare che l'utente sia ancora valido
  • SE VALIDA:
    • Confronta il token di aggiornamento con DB (supponi che corrisponda per il resto di questo)
    • Genera nuovo token di aggiornamento, sovrascrivi il valore precedente in DB
    • Reimposta JWT con nuova exp data
    • Passa nuovamente il token di aggiornamento e archivia in localStorage
  • SE NON VALIDO:
    • Cancella cookie JWT di a) impostando su un valore non valido, b) impostando la scadenza su passato
    • Dire al browser di cancellare il token CSRF localStorage
    • Cancella tutti i token di aggiornamento per l'utente da DB

TL veloce e sporco; DR

  • Al momento dell'accesso, aggiungi un token CSRF casuale al JWT.
  • Invia lo stesso token CSRF al client nel corpo della risposta.
  • Archivia il token CSRF in localStorage.
  • Includi un token di aggiornamento nel JWT.
  • Imposta il cookie JWT per scadere dopo 1 settimana.
  • Imposta la rivendicazione JWT exp a 30 minuti.
  • Se il reclamo JWT è scaduto, verifica il token di aggiornamento sul DB per verificare che l'utente sia ancora valido.
  • SE UTENTE VALIDO:
    • Problema JWT aggiornato con nuovo token CSRF e nuovo token di aggiornamento.
    • Imposta la scadenza del cookie JWT a una settimana in futuro. (riemettere il cookie, in pratica)
    • Invia un nuovo token CSRF nel corpo della risposta, sovrascrivi il valore di localStorage esistente.
  • SE NON VALIDO L'UTENTE:
    • Restituisce il cookie JWT con lo stesso nome ma nessun contenuto.
    • Imposta la scadenza del cookie su una data arbitraria nel passato.
    • Chiedi al browser di cancellare il valore di LocalStorage.
posta vaindil 13.08.2016 - 01:49
fonte

3 risposte

7

Sembra che tu stia mescolando diverse tecnologie opposte e non chiarisci il motivo per cui hai scelto queste tecnologie e perché controllano le minacce che stai cercando di ottenere.

JWTs are stored in an access_token cookie. They are first signed then encrypted using jose-jwt.

C'è qualche ragione per cui sono crittografati? La firma viene utilizzata quando si desidera verificare l'integrità dei dati, ad esempio che non è stata modificata da nessuno senza la chiave. La crittografia viene utilizzata quando si desidera proteggere la riservatezza dei dati, ad esempio che non può essere letta da nessuno senza la chiave. Se non c'è nulla nel token che non dovrebbe essere in grado di essere letto dall'utente finale, non c'è motivo di crittografarlo.

JWTs include a cst claim that stores a randomly-generated CSRF token. The CSRF token is sent in the response body upon login and when a new JWT is issued. The CSRF token is stored in the browser's localStorage. It is sent with every request and validated against the value in the JWT.

Sembra un'implementazione del Double Submit Cookie controllo CSRF. localStorage è protetto dalla Same Same Policy che impedisce ad un'altra sessione web nel browser dell'utente di accedere al token.

Assicurati che il token CSRF abbia almeno 128 bit di entropia.

As the JWTs expire in 30 minutes, it is necessary to refresh them. The JWT includes an rfs claim that stores a random refresh token. This refresh token is also stored in the DB (a separate table from users to allow for multiple sessions). If the JWT is expired (based on its exp claim), the DB is checked to ensure the user is still valid (e.g. account not deleted, password not changed, etc.). If the user is valid, the refresh token is verified and a new JWT/CSRF token are generated and passed back in the response.

Qui è dove le cose si confondono. Il modello di sicurezza dovrebbe decidere in entrambe le sessioni lato client o sessioni lato server. I JWT sono solitamente impiegati per il primo. Cioè, se si ha un token nel client firmato da una chiave disponibile solo per il server, la propria applicazione dovrebbe essere fiduciosa che la presenza di questo token denoti una sessione valida nel caso non fosse scaduta e che la firma sia valida.

Lo svantaggio di questo metodo è che è difficile revocare i token. Se un account utente viene compromesso e un utente cambia la sua password, tutte le sessioni di attacker saranno ancora attive per 30 minuti perché hanno ancora un token valido, non scaduto e firmato.

La soluzione per questo è implementare invece le sessioni lato server. Ad esempio, si tiene traccia delle sessioni in una tabella di database, il che significa che possono essere disconnessi immediatamente rimuovendo la riga nel database. Il token di sessione può essere una stringa casuale entropy a 128 bit, fornita come cookie lato client e archiviata con hash SHA-256 lato server per mitigare eventuali perdite di dati dal database. È sempre possibile inviare una data di scadenza in testo normale con il proprio cookie, in modo che il client sappia quando è necessario aggiornare il token. per esempio. un cookie HttpOnly per il token e un cookie non HttpOnly contenente la scadenza in modo che il codice JavaScript del client possa leggerlo. HttpSolo i cookie possono aiutare a mitigare l'impatto di un difetto XSS.

Pertanto, se stai monitorando le sessioni lato server, c'è un piccolo vantaggio di avere un client JWT firmato. Il codice extra significa più superficie di attacco e più possibilità di introdurre vulnerabilità nel codice in eccesso. La complessità in un'applicazione è spesso inversa rispetto alla sicurezza.

Se si utilizza Double Submit Cookie in combinazione con una sessione lato server per lo stato sessione, è consigliabile utilizzare un cookie diverso per il token CSRF. Ciò consentirà di aggiungere il token CSRF come intestazione utilizzando il codice lato client senza rischiare il token dell'identificatore di sessione. Nota che se stai impostando intestazioni personalizzate e non implementando CORS, allora questo può attenuare un po 'CSRF . Si consiglia di utilizzare anche un token, perché le tecnologie come Flash tendono a disturbare la sicurezza del browser (Flash significa più codice in esecuzione, più codice dà più superficie di attacco, più codice significa più possibilità di vulnerabilità).

    
risposta data 21.08.2016 - 21:26
fonte
2

Aggregazione dai commenti:

  • JWT come credenziale di portatore in un'app per pagina singola che comunica con API su server su ajax ha senso.
  • L'uso dei cookie in una singola pagina dell'app non ha senso. Se tutte le richieste al collo di bottiglia dell'API del server tramite una funzione Ajax, tale funzione può includere JWT in un'intestazione. Se non ci sono cookie, allora non c'è CSRF, perché le richieste provenienti dai frame in attacco non passeranno attraverso la funzione Ajax
  • L'utilizzo di script di terze parti è ovviamente pervasivo, ma è comunque un grosso rischio per la sicurezza. Gli script di terze parti operano all'interno dello stesso contesto javascript e DOM e possono vedere l'intero DOM. Se sono dannosi, ci sono molte, molte opzioni di attacco. Se possibile, elimina gli script di terze parti o assicurati che siano verificati, utilizzando l'integrità delle risorse secondarie o altri mezzi (ad esempio, monitorali per le modifiche).
  • localStorage segue lo stesso criterio di origine e può essere trattato come una cache client per DOM o dati di autorizzazione. In una SPA, la JWT può essere mantenuta in localStorage, perché segue lo stesso modello di sicurezza del DOM.
  • È possibile mantenere un token di aggiornamento nel JWT
  • La scadenza JWT e le vite di aggiornamento sono difficili da commentare in astratto. È importante trovare il giusto equilibrio tra sicurezza e usabilità, non richiedere agli utenti di saltare gli ostacoli a meno che non vi siano buone ragioni e fornire agli utenti la garanzia giusta in caso di dubbi.

Altre cose da fare:

  • Applicare https e utilizzare le intestazioni del protocollo delle risorse correlate come x-frame-options, strict transport security e policy di sicurezza del contenuto
  • Conserva alcuni metadati della versione specifica dell'app Pagina singola nel JWT e richiede un aggiornamento successivo all'aggiornamento delle app
  • Mantieni i metadati del client in particolare nel JWT. Non consentire l'utilizzo di un browser desktop JWT da un browser mobile.
  • Avere la possibilità dal server di revocare tutti i JWT e i token di aggiornamento associati a un utente. Se un utente ha JWT e aggiorna gettoni legati al telefono e al desktop e ti dice che ha perso il telefono, probabilmente vorrai invalidare i loro JWT del telefono e del desktop e aggiornare i token.
  • Avere un'autorizzazione a livello di oggetto / operazione avanzata sull'API del server - ovvero, verificare l'integrità del JWT, confermare l'autorizzazione che i pacchetti non sono stati revocati e quindi verificare che le attestazioni in esso contenute forniscano l'accesso appropriato all'API, prima di eseguire qualsiasi operazione API.
risposta data 21.08.2016 - 20:05
fonte
1

Questo suona abbastanza bene per me (anche la soluzione CSRF è carina) fino alla parte Aggiorna token.

Uno dei vantaggi che vedo in un sistema basato su JWT è che i token di accesso scadono regolarmente. Ciò significa che un token di accesso JWT compromesso consente solo a un utente malintenzionato di accedere per un periodo di minuti o ore.

Se includi il token di aggiornamento nel JWT, un utente malintenzionato che compromette la JWT può utilizzarlo facilmente per aggiornarsi, rendendo impossibile la data di scadenza effettiva.

Un token di accesso non dovrebbe essere in grado di concedere un nuovo token di accesso. Solo un token di aggiornamento (o autenticazione completa) dovrebbe essere in grado di concedere un nuovo token di accesso.

    
risposta data 06.12.2017 - 03:18
fonte

Leggi altre domande sui tag