Protezione delle password per l'autenticazione REST

4

Sto sviluppando un'applicazione REST utilizzando Spring Framework, come parte dei requisiti, dobbiamo proteggere le diverse funzioni del sistema in ruoli utente diversi (cose piuttosto standard). Il mio attuale metodo per determinare i ruoli per l'utente attualmente connesso è che ogni volta che chiamano un URL REST dal frontend, aggiungo una stringa codificata Base 64 all'intestazione della richiesta. Questa stringa quando decodificata risolve il nome utente e un hash della password generato da bCrypt in questo formato nome utente: hashedpassword.

Sono un po 'preoccupato che questo non sia sicuro, anche se la richiesta verrà effettuata tramite una connessione HTTP sicura, perché potrebbe consentire a un potenziale hacker di accedere almeno al nome utente degli utenti. Non è stato possibile ottenere la password perché si tratta solo di un valore hash, ma potrebbero utilizzare tale valore hash per chiamare correttamente l'API REST.

Come posso proteggere correttamente questo sistema? Devo aggiungere un token di sessione o un qualche tipo di chiave generata a caso per la sessione?

La mia domanda successiva è quindi come posso farlo RESTfully? Stavo pensando che potrei generare (usando bCrypt) un hash che rappresenta il nome utente: hashedpassword insieme al login, salvarlo nel database e verificarlo quando viene effettuata una chiamata REST. Quando l'utente si disconnette, basta impostarlo su null. Risciacqua e ripeti. In questo modo qualsiasi potenziale aggressore otterrebbe una sola stringa bCrypt che non avrebbe rivelato il nome utente, ma potrebbe comunque usare quella stringa per chiamare l'API REST.

    
posta JamesENL 14.04.2014 - 09:19
fonte

2 risposte

4

I seguenti collegamenti potrebbero fornire una risposta approfondita:

Tieni presente che è meglio non utilizzare la combinazione nome utente-password in ogni richiesta effettuata. È meglio autenticare l'utente, generare un token lato server, comunicarlo al client (ad esempio in un cookie) e utilizzare quel token come autenticazione per le richieste successive. Questo link può guidarti in questo processo: link .

    
risposta data 14.04.2014 - 09:56
fonte
0

Se hai solo bisogno di fornire l'autenticazione ma i dati trasmessi via cavo non sono sensibili, allora c'è un modo migliore senza il sovraccarico / la latenza di SSL.

Supponiamo di avere un'app client mobile; per prima cosa iscrivere o registrare l'utente fornendo la propria email (nome utente) e la password in un modulo Web separato (non facente parte dell'app o del servizio REST). Quindi, una volta completata la registrazione, si risponde con una chiave utente (può essere una chiave segreta condivisa memorizzata nell'account utente sul server (database) per la crittografia simmetrica o una chiave pubblica per la crittografia asimmetrica in cui la chiave privata corrispondente è memorizzata nell'account utente sul server (database). Tutto questo viene fatto utilizzando un modulo Web su SSL.

Ora, quando l'utente apre l'app client, è necessario chiedere loro le credenziali che verranno inviate con ogni richiesta al servizio RESTful. Devono fornire il loro nome, password e chiave di crittografia che hanno ricevuto in precedenza. Questo deve essere fatto solo una volta. L'app fornisce quindi un header http con ogni richiesta che assomiglia a questo:

AUTENTICAZIONE > username: timestamp: crittografato {password: timestamp} / AUTHENTICATE >

Si noti che sia la password che il timestamp all'interno di {} vengono crittografati utilizzando la chiave dell'utente. Il timestamp viene aggiornato con ogni singola richiesta.

Implementa un filtro di autenticazione sul server che effettua le seguenti operazioni:

Prima controlla il timestamp e se scaduto (diciamo più vecchio di 1 secondo) invia un codice di risposta HTTP NON AUTORIZZATO. Se il timestamp è valido, cerca il nome utente nel tuo database degli account utente. Se non trovato, invia una risposta HTTP NON AUTORIZZATA. Se viene trovato il nome utente, recuperare la chiave di crittografia memorizzata per quell'utente (ricordare che questa può essere una chiave segreta condivisa o la chiave privata per la chiave pubblica dell'utente). Decifrare la {password: timestamp} crittografata. La password rifiutata deve corrispondere alla password dell'utente memorizzata nel database (la password stessa potrebbe anche essere inclusa nel database utilizzando un'altra chiave per maggiore sicurezza) e la data / ora decrittografata deve corrispondere anche al timestamp non crittografato inviato nell'intestazione AUTHENTICATE sopra. In caso contrario, inviare un codice di risposta HTTP NON AUTORIZZATO. In caso di esito positivo la richiesta è stata autenticata senza l'uso di cookie / sessioni.

Puoi anche memorizzare nella cache i dettagli dell'utente per evitare di eseguire una ricerca nel database ad ogni richiesta.

Ora, se qualcuno sta indagando e intercetta la richiesta, non sarà in grado di riutilizzarla per ottenere l'accesso perché la data / ora non sarà valida o, se aggiornerà la data / ora non crittografata per essere valida, non corrisponderà alla crittografia timestamp (dopo che il filtro di autenticazione lo ha decrittografato).

Un altro vantaggio di questo approccio rispetto all'utilizzo di una singola chiave dell'app è che ora hai il controllo completo su chi può accedere al tuo servizio inserendo una data di scadenza sull'account utente nel database (implementando in modo efficace un servizio basato su abbonamento). Questo è ottimo perché all'inizio potresti voler ottenere il maggior numero possibile di utenti con un abbonamento di prova (gratuito per esempio 1 anno) e poi bloccare l'accesso a quell'utente se non hanno pagato per estendere la data di scadenza dell'account:)

    
risposta data 10.05.2014 - 10:04
fonte

Leggi altre domande sui tag