La mia applicazione è costituita da un'API back-end nodejs, ma sto anche sviluppando un'implementazione di "riferimento" di un client JavaScript, che è un backbone SPA .
Prima di tutto; l'API accetta solo le richieste HTTPS, nel caso in cui una richiesta HTTP raggiunga il server, la ignora completamente e inoltre (a seconda della configurazione del tenant) invalida la password fornita su quella richiesta non sicura.
Il mio server è stateless e sto usando solo l'autenticazione di base HTTP (S) . Fornisco due modi per autenticare una richiesta:
1- Invio delle credenziali sull'intestazione Authentication: base64('Basic ' + user:password)
2- Invio di una richiesta autenticata utilizzando il metodo 1 a GET /users/current
che restituisce un token che è una stringa crittografata * contenente: username + '|' + timeOfTokenExpiration
. Quindi il client invia solo l'intestazione Authentication: base64('Token ' + username:returnedToken)
in seguito.
* La crittografia viene eseguita con l'algoritmo aes-256-ctr di OpenSSL e la chiave è l'hash della password dell'utente
Metodo 1 può essere utilizzato per una comunicazione diretta da server a server, ma non è adatto per un client JavaScript poiché l'utente dovrebbe inserire le sue credenziali su ogni richiesta, ciò che è impossibile .
L'archiviazione delle credenziali dell'utente nella memoria locale del browser risolverebbe questo problema ma manterrebbe l'utente a tempo indefinito, creando un'altra possibile minaccia alla sicurezza. Inoltre, non sono sicuro di quanto sia sicuro archiviare le credenziali in testo non crittografato nella memoria del browser .
Utilizzando il metodo 2 il client JavaScript invierà solo una richiesta autenticata e quindi memorizzerà le credenziali crittografate sull'archiviazione locale, dopo un certo periodo di tempo dovrà riconvalidare le credenziali dell'utente poiché alla fine scadrà e il server non accetterà richieste da quel token.
Sul lato server controllo l'autenticità di una richiesta del metodo 2 recuperando l'hash della password dell'utente e cercando di decodificarlo. Dopo la decifrazione, controllo se decryptedString.split('|')[0] === username
.
È un approccio sicuro / buono?