2015-03-07 2 views
34

Ho un'applicazione Spring REST che inizialmente era protetta con l'autenticazione di base.La protezione di un'applicazione REST con autenticazione JWT e di base ha senso?

Quindi ho aggiunto un controller di accesso che crea un token Web JSON JWT utilizzato nelle richieste successive.

Posso spostare il seguente codice dal controller di accesso e nel filtro di sicurezza? Quindi non avrei più bisogno del controller di login.

tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail()); 

Oppure è possibile rimuovere l'autenticazione di base?

È un buon progetto per unire l'autenticazione di base con un JWT?

Anche se funziona tutto bene, sono un po 'al buio qui per progettare al meglio questa sicurezza.

+0

Come viene inviato il token al server nelle richieste successive? (Intestazione HTTP? Cookie?). Inoltre, stai usando TLS (SSL)? –

+0

Ciao Les, è bello vederti spuntare di nuovo! Sì, il token viene inviato come intestazione X-Auth-Token. Sto anche usando TLS. TLS è obbligatorio quando si utilizza un JWT? – Stephane

+0

Ciao Stephane! :) Se il JWT rappresenta un'identità verificata, sì, considererei obbligatorio TLS, altrimenti è (molto) più facile per gli attacchi MITM. –

risposta

66

Supponendo TLS 100% per tutte le comunicazioni, sia durante che dopo l'accesso, l'autenticazione con nome utente/password tramite l'autenticazione di base e la ricezione di un JWT in cambio è un caso d'uso valido. Questo è quasi esattamente come funziona uno dei flussi di OAuth 2 ('password grant').

L'idea è che l'utente finale sia autenticato tramite un endpoint, ad es. /login/token utilizzando qualsiasi meccanismo che si desidera e la risposta deve contenere il JWT che deve essere restituito a tutte le richieste successive. Il JWT dovrebbe essere un JWS (vale a dire un JWT crittografato) con un campo di scadenza JWT appropriato (exp): ciò garantisce che il client non possa manipolare il JWT o farlo vivere più a lungo di quanto dovrebbe.

Non hai bisogno di un header X-Auth-Token sia: lo schema di autenticazione HTTP Bearer è stato creato per questo caso esatto uso: in pratica qualsiasi bit di informazione che sentieri il nome schema Bearer è informazione 'portatore' che dovrebbe essere convalidato. Basta impostare il Authorization intestazione:

Authorization: Bearer <JWT value here> 

Ma, detto questo, se il client REST è 'attendibile' (browser ad esempio JavaScript abilitato), non voglio fare nemmeno quello: qualsiasi valore nella risposta HTTP che è accessibile tramite JavaScript - praticamente qualsiasi valore di intestazione o valore del corpo della risposta - potrebbe essere annusato e intercettato tramite attacchi MSS XSS.

È meglio memorizzare il valore JWT in un cookie solo sicuro, http-only (cookie config: setSecure (true), setHttpOnly (true)). Ciò garantisce che il browser:

  1. sempre e solo di trasmettere il cookie tramite una connessione TLS e,
  2. mai fare il valore del cookie disposizione di codice JavaScript.

Questo approccio è quasi tutto ciò che è necessario fare per la sicurezza delle best practice. L'ultima cosa è assicurarsi di avere una protezione CSRF su ogni richiesta HTTP per garantire che i domini esterni che avviano richieste al tuo sito non possano funzionare.

Il modo più semplice per farlo è impostare un cookie sicuro solo (ma NON solo http) con un valore casuale, ad es. un UUID.

Quindi, su ogni richiesta nel server, assicurarsi che il proprio codice JavaScript legga il valore del cookie e lo imposti in un'intestazione personalizzata, ad es. X-CSRF-Token e verificare quel valore su ogni richiesta nel server. I client di dominio esterni non possono impostare intestazioni personalizzate per le richieste al tuo dominio a meno che il client esterno non ottenga l'autorizzazione tramite una richiesta di Opzioni HTTP, quindi qualsiasi tentativo di attacco CSRF (ad esempio in un IFrame, qualunque cosa) non andrà a buon fine.

Questa è la migliore protezione disponibile per i client JavaScript non attendibili sul web che conosciamo oggi. Stormpath ha scritto un articolo su these techniques e anche se sei curioso.

Infine, il Stormpath Java Servlet Plugingià fa tutto questo per voi (e molto più roba fresca, comprese le ulteriori controlli di sicurezza automatizzati), in modo da non mai a scriverlo - o peggio - mantenere da soli. Guarda il HTTP Request Authentication section e l'esempio Form/Ajax per vedere come usarlo. HTH!

+1

Bella risposta Les e grazie. Ricordo che ho aggiunto il controller di accesso in un secondo momento nello sviluppo dell'app, quando ho appreso e implementato l'autenticazione del token JWT nell'app. In effetti non sono riuscito a capire come creare il token all'interno del filtro Spring Security auth di base. Leggendo la tua soluzione, vedo che è come potrei e dovrei farlo, e rimuovere del tutto il controller di accesso poiché non è necessario ... – Stephane

+0

Ciao Les, stavo per sostituire l'intestazione X-Auth-Token con l'autorizzazione standard intestazione usando il prefisso Bearer. Questo è il momento in cui sono incappato in una risposta affermando che non dovrei usare un'intestazione standard e invece usarne una personalizzata. Il suo punto è che questa intestazione standard dovrebbe essere lasciata all'autenticazione di base. Vedi http://stackoverflow.com/questions/12086041/basic-authentication-with-a-guid-token-for-rest-api-instead-of-username-password Puzzled ... – Stephane

+0

@StephaneEybert Ho aggiunto una risposta a quel filo. L'intestazione 'Autorizzazione' supporta molti _schemi_. Puoi usare qualunque schema tu voglia. 'Basic' rappresenta un algoritmo. 'Bearer' è qualunque sia il testo che lo segue (nessun algoritmo). Altri schemi (come 'Digest') usano un algoritmo diverso. Potresti persino inventare il tuo schema. Il punto è che l'intestazione è la stessa, ma i nomi degli schemi e i valori del testo finale riflettono il comportamento esatto. Mi dilungo su questo [qui] (http://stackoverflow.com/a/14046557/407170) –