Il problema
Attualmente sto progettando il backend per una SPA (Single Page Application), che sto progettando di costruire in modo abbastanza RESTful. Il back-end sarà idealmente solo un sottile strato tra il client e il database. Quasi tutti i dati nel database saranno adattati a un utente specifico, motivo per cui ho bisogno di qualche forma di sistema di autenticazione.
Dato che viviamo in un universo in cui gli esseri umani sono abbastanza prevedibili e le macchine possono essere veramente molto veloci, dobbiamo ovviamente rendere lento l'hashing della password e la verifica della password (normalmente usando schemi di stretching chiave come bcrypt o whatnot ). Tutto questo è bello e dandy, ma complica la vita per noi poveri che vogliono progettare applicazioni veloci e scattanti usando un backend RESTful, perché idealmente un back-end non avrebbe bisogno di memorizzare alcun dato di sessione, ma solo autenticare ogni singola richiesta individualmente ( utilizzando ad esempio l'autenticazione di accesso di base).
Tuttavia ciò significherebbe hashing della password degli utenti per ogni singola richiesta, che aggiungerebbe una penalità dolorosa per ogni richiesta (e probabilmente rendendo più facili gli attacchi DDoS). Ovviamente questo problema può essere risolto memorizzando nella cache le credenziali dell'utente nel back-end, ma questa soluzione non sembra molto pulita e solleva alcuni altri problemi, come la gestione del ritiro della cache e la costrizione del client a memorizzare le credenziali in testo semplice. / p>
Quindi, in breve, il mio problema è che ho bisogno di qualche forma di sistema per gestire l'autenticazione degli utenti in modo rapido, ma idealmente posso ancora evitare qualsiasi stato lato server.
La mia soluzione proposta
Prima di tutto il traffico tra il client e il server verrà crittografato usando TSL standard di boog, quindi non dovremmo essere vulnerabili agli intercettatori né agli attacchi man-in-the-middle.
La soluzione che ho pensato è di rilasciare un token al client, dopo l'autenticazione iniziale riuscita utilizzando le credenziali inviate in testo normale su TSL, che contiene le informazioni necessarie necessarie al server per autenticare un utente. Questo token verrebbe calcolato nel modo seguente:
key = a random key generated when the server starts, never to be shared
nonce = just some random bytes grabbed out of the air
token = nonce + timestamp + user_id + HMAC(key, nonce + timestamp + user_id)
Ciò consentirebbe al server di verificare se il token è valido semplicemente convalidando l'HMAC per ogni richiesta, il che è molto economico da fare (economico quanto fare una ricerca in una tabella hash, ma eliminando del tutto la necessità di tabella hash in primo luogo). Se il token è valido e non è scaduto (non è consentito che il timestamp sia troppo vecchio) lascio che la richiesta proceda e consenta al database di gestire il problema dell'autorizzazione.
Questo sembra un modo per autenticare in modo efficiente e sicuro gli utenti, oltre a richiedere sorprendentemente pochi LoC da implementare oltre a evitare totalmente qualsiasi tipo di stato nel back-end (l'applicazione server userebbe una quantità costante di memoria per tutta la sua durata ).
La mia vera domanda
Ora questo schema può sembrare totalmente distruttivo a prima vista, ma dopo averlo osservato un po 'vedo due potenziali problemi che fanno sorgere delle domande:
-
Non c'è modo di ritirare un token, tranne aspettare che scada. Questo è davvero un problema o sono io essere paranoico? Dal momento che deve essere memorizzato sul lato client, la sicurezza viene immediatamente compromessa se una parte malintenzionata accede a un client prima che il token scada. Certo, il pericolo è contenuto nel periodo di tempo in cui il token è valido, ma per questo SPA che il tempo potrebbe essere contato in giorni.
-
Come si scala? La chiave del lato server segreto dovrebbe essere condivisa tra tutti i server del cluster, ma come dovremmo farlo in modo sicuro e quando dovremmo ritirare una chiave lato server?
Potrebbero esserci anche altri problemi, ma questi sono i due evidenti che si sono distinti per me. Cosa ne pensi di questo schema e di questi problemi?
Si noti che questa domanda non è una domanda generale sulla generazione sicura di token o sulla gestione delle sessioni (come è stato risposto molte volte qui), ma sui problemi periferici riguardanti questo schema specifico, problemi che non ho visto discusso.