Gestione del rinnovo del token / scadenza della sessione in un'API RESTful


17

Sto creando un'API RESTful che utilizza i token JWT per l'autenticazione dell'utente (emessi da un loginendpoint e successivamente inviati in tutte le intestazioni) e i token devono essere aggiornati dopo un determinato periodo di tempo (invocando un renewendpoint, che restituisce un token rinnovato ).

È possibile che la sessione API di un utente diventi non valida prima della scadenza del token, quindi tutti i miei endpoint iniziano verificando che: 1) il token sia ancora valido e 2) la sessione dell'utente sia ancora valida. Non è possibile invalidare direttamente il token, poiché i client lo memorizzano localmente.

Pertanto, tutti i miei endpoint devono segnalare ai miei clienti due possibili condizioni: 1) che è tempo di rinnovare il token o 2) che la sessione è diventata non valida e non è più consentito loro di accedere al sistema. Posso pensare a due alternative per i miei endpoint di segnalare i loro clienti quando si verifica una delle due condizioni (supponiamo che i client possano essere adattati a entrambe le opzioni):

  1. Restituisce un codice http 401 (non autorizzato) se la sessione è diventata non valida o restituisce un codice 412 (condizione preliminare non riuscita) quando il token è scaduto ed è tempo di chiamare l' renewendpoint, che restituirà un codice 200 (ok).
  2. Restituisce 401 per segnalare che la sessione non è valida o che il token è scaduto. In questo caso il client chiamerà immediatamente l' renewendpoint, se restituisce 200, il token viene aggiornato, ma se renewrestituisce anche 401, significa che il client è fuori dal sistema.

Quale delle due alternative sopra mi consiglieresti? Quale sarebbe più standard, più semplice da capire e / o più RESTful? O consiglieresti un approccio completamente diverso? Vedi qualche ovvio problema o rischio per la sicurezza con entrambe le opzioni? Punti extra se la tua risposta include riferimenti esterni a supporto della tua opinione.

AGGIORNARE

Ragazzi, concentratevi sulla vera domanda: quale delle due alternative al codice http per segnalare un rinnovo / invalidamento della sessione è la migliore? Non importa il fatto che il mio sistema utilizzi JWT e sessioni lato server, questa è una peculiarità della mia API per regole aziendali molto specifiche e non la parte per cui sto cercando aiuto;)


In che modo la sessione di un utente diventerebbe non valida prima della scadenza del token, ipotizzando un tempo di scadenza breve (circa 5 minuti)?
Jack,

A causa di una regola aziendale, una parte diversa del sistema potrebbe invalidare la sessione.
Óscar López,

1
I JWT sono per la prova dell'identità, come in "questa richiesta è provata dall'utente X". Se la regola aziendale è qualcosa del tipo "l'utente X non può più interagire con la risorsa Y", è qualcosa che dovrebbe essere controllato separatamente dal JWT.
Jack,

@ Jack esattamente! questo è esattamente il mio punto e il motivo per cui devo usare un livello aggiuntivo e con stato per salvare le informazioni sulla sessione. Il semplice JWT, per quanto bello, non è adatto per il lavoro.
Óscar López,

1
Potresti essere interessato alla mia risposta allora :)
Jack

Risposte:


22

Sembra un caso di autenticazione contro autorizzazione .

I JWT sono affermazioni con firma crittografica sull'autore di una richiesta. Un JWT potrebbe contenere dichiarazioni come "Questa richiesta è per l'utente X" e "L'utente X ha ruoli di amministratore". Ottenere e fornire questa prova tramite password, firme e TLS è il dominio di autenticazione , a dimostrazione del fatto che sei chi dici di essere.

Ciò che tali affermazioni significano per il tuo server - ciò che gli utenti e i ruoli specifici sono autorizzati a fare - è il problema dell'autorizzazione . La differenza tra i due può essere descritta con due scenari. Supponiamo che Bob voglia entrare nella sezione di deposito limitato del magazzino della sua azienda, ma prima deve occuparsi di una guardia di nome Jim.

Scenario A - Autenticazione

  • Bob: "Ciao Jim, vorrei entrare in un archivio limitato."
  • Jim: "Hai il tuo distintivo?"
  • Bob: "No, l'ho dimenticato."
  • Jim: "Mi spiace amico, nessuna voce senza badge."

Scenario B - Autorizzazione

  • Bob: "Ciao Jim, vorrei entrare in un deposito limitato. Ecco il mio badge."
  • Jim: "Ehi Bob, devi entrare al livello 2 per entrare qui. Mi dispiace."

I tempi di scadenza di JWT sono un dispositivo di autenticazione utilizzato per impedire ad altri di rubarli. Se tutti i tuoi JWT hanno una scadenza di cinque minuti, non è un grosso problema se vengono rubati perché diventeranno rapidamente inutili. Tuttavia, la regola "Scadenza sessione" discussa sembra un problema di autorizzazione. Alcuni cambiamenti di stato indicano che all'utente X non è più permesso fare qualcosa che era in grado di fare. Ad esempio, l'utente Bob potrebbe essere stato licenziato - non importa che il suo badge dica che è più Bob, perché il semplice fatto di essere Bob non gli conferisce più alcuna autorità alla compagnia.

Questi due casi hanno codici di risposta HTTP distinti: 401 Unauthorizede 403 Forbidden. Il codice sfortunatamente denominato 401 è per problemi di autenticazione come credenziali mancanti, scadute o revocate. 403 è per l'autorizzazione, in cui il server sa esattamente chi sei, ma non ti è permesso fare ciò che stai tentando di fare. Nel caso in cui un account utente venisse eliminato, il tentativo di fare qualcosa con un JWT in un endpoint comporterebbe una risposta proibita 403. Tuttavia, se il JWT è scaduto, il risultato corretto sarebbe 401 Non autorizzato.

Un modello JWT comune è quello di avere token "longevi" e "di breve durata". I token di lunga durata vengono archiviati sul client come token di breve durata, ma sono di portata limitata e utilizzati solo con il sistema di autorizzazione per ottenere token di breve durata. I token di lunga durata, come suggerisce il nome, hanno periodi di scadenza molto lunghi: puoi usarli per richiedere nuovi token per giorni o settimane. I token di breve durata sono i token che stai descrivendo, utilizzati con tempi di scadenza molto brevi per interagire con il sistema. I token di lunga durata sono utili per implementare la funzionalità Ricordami, quindi non è necessario fornire la password ogni cinque minuti per ottenere un nuovo token di breve durata.

Il problema di "invalidazione della sessione" che stai descrivendo sembra simile al tentativo di invalidare un JWT di lunga durata, poiché quelli di breve durata vengono raramente archiviati sul lato server mentre quelli di lunga durata vengono tracciati nel caso in cui debbano essere revocati. In un tale sistema, il tentativo di acquisire credenziali con un token di lunga durata revocato comporterebbe 401 Non autorizzato, poiché l'utente potrebbe tecnicamente essere in grado di acquisire credenziali ma il token che sta utilizzando non è adatto all'attività. Quindi, quando l'utente tenta di acquisire un nuovo token di lunga durata utilizzando il nome utente e la password, il sistema potrebbe rispondere con 403 Proibito se viene espulso dal sistema.


3
Questa è la guida che stavo cercando e tu hai fornito una visione molto rilevante della discussione - che questo è un caso di autenticazione contro autorizzazione, e ognuno dovrebbe essere trattato in modo diverso. Grazie!
Óscar López,

16

La tua sessione API è una cosa che non dovrebbe esistere affatto in un mondo RESTful. Le operazioni RESTful dovrebbero essere apolidi, la sessione contiene stato e quindi non ha spazio in un mondo RESTful.

Il JWT dovrebbe essere l'unico modo per determinare se un utente è ancora idoneo ad accedere a un endpoint o meno. Una sessione non dovrebbe assolutamente svolgere alcun ruolo in essa. In tal caso, non hai un'API RESTful.

Quando si elimina del tutto la sessione, cosa che si dovrebbe fare se si desidera un'API RESTful e si utilizza JWT solo come fattore di autenticazione, un utente è autorizzato a utilizzare l'endpoint oppure no, nel qual caso il 401 Unauthorizedcodice di risposta è appropriato - e dovrebbe chiamare l' renewendpoint con grant_type=refresh_tokeno qualunque identificazione del rinnovo che si sta utilizzando.

Aggiornare:

Dal commento sembra che il flusso di convalida del JWT attualmente in uso non sia corretto. La convalida dovrebbe apparire così:

  Client        RESTful API      JWT Issuer
     |              |                |
     |----- 1. ---->|                | 
     |              |------ 2. ----->|-----
     |              |                | 3. |
     |              |<----- 4. ------|<----
-----|<---- 5. -----|                |
| 6. |              |                |
---->|----- 7. ---->|                |
     |              |------ 8. ----->|-----
     |              |                | 9. |
     |              |<----- 10. -----|<----
     |              |                |
     |              |------          |
     |              | 11. |          |
     |<---- 12. ----|<-----          |
     |              |                |
     .              .                .

1. Ask RESTful API for a JWT using login endpoint.
2. Ask Issuer to create a new JWT.
3. Create JWT.
4. Return JWT to the RESTful API.
5. Return JWT to Client.
6. Store JWT to append it to all future API requests.
7. Ask for data from API providing JWT as authorization.
8. Send JWT to Issuer for verification.
9. Issuer verifies JWT.
10. Issuer returns 200 OK, verification successful.
11. Retrieve and format data for Client.
12. Return data to Client.

Il server RESTful APIdeve verificare la validità del token che viene inviato come autorizzazione. Questa non è responsabilità del Client. Sembra che al momento non lo stia facendo. Implementa la verifica del JWT in questo modo e non hai bisogno di sessioni.


Grazie per la tua risposta. D'accordo, l'uso di una sessione non sarebbe un approccio RESTful al 100%, ma come ho detto sopra, devo negare l'accesso ad alcuni utenti prima della scadenza del token.
Óscar López,

2
@ ÓscarLópez Quindi semplicemente invalidare i token utilizzati dagli utenti. Non saranno più in grado di accedere all'API utilizzando il token fornito (che ora sarà stato invalidato) e non è necessaria una sessione.
Andy,

1
I token sono memorizzati sul client, come posso invalidarli lì? Dovrei tenere traccia di quali sono validi ... ed è qui che lo stato impenna la sua brutta testa. A volte è inevitabile.
Óscar López,

Un client malintenzionato potrebbe continuare a inviare un token precedentemente valido fino a quando il suo tempo di scadenza lo consente, ma devo eliminarlo immediatamente dal sistema, quindi l'impostazione di un breve periodo di rinnovo non è un'opzione.
Óscar López,

4
@Laiv Ho creato il diagramma di sequenza nel blocco note.
Andy,

1

Quindi, confesserò che non ha molto senso per me essere preoccupato per quale approccio è più RESTful quando stai già rompendo le convenzioni REST con la sessione, ma capisco di soddisfare le tue esigenze aziendali.

Da un punto di vista REST, il client è autenticato o non lo è. L'architettura non si preoccupa molto del perché (che sta iniettando lo stato inutile), quindi per rispondere alla tua domanda principale, non avrei affatto un endpoint di rinnovo. Un client connesso invierà sempre il proprio JWT e il server lo convaliderà sempre e lo accetterà inviando il codice Success appropriato basato sull'azione 200, 201, ecc.) O rifiuterà con un 401 o 403 come appropriato.

Ora, il JWT verrà associato a un account di qualche tipo. Tale account potrebbe essere bloccato o limitato o altro, quindi il token stesso potrebbe essere valido ma l'azione potrebbe essere comunque rifiutata altrove. Se il caso è che l'account utente è bloccato a causa delle regole aziendali, allora è ancora un 401 o 403 a seconda di quante informazioni vuoi fornire al cliente (diverse aziende hanno opinioni diverse su questo).

Infine, se stai affermando che l'account potrebbe essere sbloccato e valido ma il JWT deve solo essere revocato, allora continuerei ancora con il 401 o il 403 e manterrei qualcosa come un Elenco di revoche di certificati di JWT non validi in cui puoi inserirne uno , purché si pulisca da solo quando il JWT sarebbe scaduto (la maggior parte dei database ha un modo per farlo o puoi avere eventi nel codice dell'app).


jwt è pensato per essere apolide. nel momento in cui metti in discussione il suo contenuto e lo convalidi contro un db, non è più apolide quindi diventa ridondante in quanto esistono soluzioni migliori per le sessioni statefull
Stavm
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.