Come salvare le password nel database per creare un login sicuro
23 Nov 2017
Reading time ~4 minutes
Si sa, l’utente medio usa una password unica per tutti i vari siti a cui si iscrive. Ma quanti di questi si chiedono come sono salvate le loro password all’interno di questi siti? Lo scopo di questo articolo è quindi di fare una breve panoramica sulle tecniche utilizzate per salvare gli utenti e la password associata nei database sui vari siti e analizzarne le criticità.
Background
Prima di iniziare ad approfondire l’argomento ci occorre conoscere il concetto di funzione hash. Questa particolare funzione la useremo infatti in alcuni dei metodi per incrementare la sicurezza del salvataggio della password.
Una funzione hash è una funzione che prende in input una qualsiasi sequenza di bit {0,1}, e ne restituisce una sequenza di lunghezza limitata.
Richiediamo, per un nostro utilizzo informatico per questo scopo, che la funzione hash sia crittograficamente sicura, cioè che
- Sia resistente alla preimmagine: sia computazionalmente intrattabile (cioè ci si impiega troppo tempo) la ricerca di una stringa in input che dia un hash uguale a un dato hash
- Sia resistente alla seconda preimmagine: sia computazionalmente intrattabile la ricerca di una stringa in input che dia un hash uguale a quello di una data stringa
- Sia resistente alle collisioni: sia computazionalmente intrattabile la ricerca di una coppia di stringhe in input che diano lo stesso hash
Una delle più famose funzioni hash è la SHA-256, che, preso in input una sequenza di bit, restituisce in output una sequenza di 256 bit.
Esempio
SHA-256(“Buongiorno a tutti!”) = a676a97982d936d0e5c0754e7f6498545e866af8a7ba5e1423e9d508a0936249
SHA-256(“Buongiorno a tutte!”) = 93506259360027cc82a29c1b7a2e5aca46df86047d2bbedc297c4754c57560e1
Bene, siamo pronti per iniziare!
Metodo 1
ID | user | password |
---|---|---|
001 | pippo | pluto |
002 | topolino | quiquoqua |
... | ... | ... |
Il primo metodo che ci può venire in mente è semplice, prendo lo username e la password dell’utente e lo inserisco nel database. Beh, un’idea più stupida vi viene in mente? Il problema nasce dal fatto che in questo modo ho inviato in chiaro la password dal client (il computer che l’utente usa per registrarsi) al server (okok, potrei usare https ma non sempre questo succede) e ho salvato tutto in chiaro nel database… e se il database viene violato? Password gratis e facili per tutti! E visto che l’utente avrà spesso la stessa password per più servizi, buona fortuna!
Metodo 2
ID | user | password |
---|---|---|
001 | pippo | bf52f397be39d08126685c32b75f44405c8b9b0876c719dea456a40780b10e0c |
002 | topolino | 73dc28b2cd5edc4bc25e095c0770c11f467ac0eb33ac26566c941cdb8b087592 |
... | ... | ... |
Il secondo metodo prevede l’utilizzo della funzione hash. L’utente al momento della registrazione invia la password, lato client (così anche in caso di Man-in-the-middle la password rimane al sicuro) viene calcolato l’hash, viene inviato l’hash al server che lo salva nel database.
Poichè la funzione hash è resistente alla preimmagine, e per sua natura non è invertibile, conoscendo il solo risultato hash, non sono in grado di risalire alla password e quindi il mio database, in caso di violazione, tiene al sicuro le password in chiaro dei miei utenti. Sbagliato!
È vero che la funzione hash è resistente alla preimmagine, è resistente alla seconda preimmagine, ma, se due utenti usano la stessa password, cosa non così fuori dal mondo, il loro hash risulterà uguale e quindi, violando il database e conoscendo la password di un utente, posso anche conoscere tutti gli altri utenti che usano la medesima password.
Metodo 3
Ed ecco quindi arrivati al metodo che di fatto dovrebbe essere usato oggi. La password salvata tramite hash con il salt.
ID | user | password | Salt |
---|---|---|---|
001 | pippo | cfb6cdfda55efb2a6d5d5d8870d2477241f97c6804a53a627645b1a66e9c2562 | 21323 |
002 | topolino | b4017d36d62a259f4619d3a2588cc1d431de53b9b0d899ebfdde9886806598c1 | 65542 |
... | ... | ... |
L’utente, al momento della registrazione inserisce la password. A tale password viene concatenato un numero generato casualmente (chiamato salt, dall’inglese chicco di sale) e viene fatto l’hash della password+salt. A questo punto viene inviata al server la coppia <hash(password+salt), salt> e salvata tale coppia nel database. L’utente, al momento del login, invia la password, il server la concatenerà con il salt, ne calcolerà l’hash e se il risultato coincide con quanto salvato nel database darà l’ok per l’autenticazione. Complicando un po’ il protocollo di login si può anche fare che il salt viene rimandato al client che spedirà solamente l’hash finale al server, sempre per evitare intercettazioni di traffico che comunque, con l’avvento dell’https sono diventate più complesse da effettuare.
Nel caso di una violazione del database le password risulteranno al sicuro perchè, pur conoscendo la password di un utente, non siamo in grado di determinare se altri utente hanno la stessa password (se non andando a ricalcolare tutti gli hash).
Precisazioni finali
Tanto per chiarezza, nessun dato possiamo ritenerlo al sicuro se è online, ma possiamo rendere la vita difficile a chi tenta di rubarlo. Conoscere l’hash non ci porta a nessun risultato utile poichè trovare una stringa che generi quell’hash vuol dire provare tutte le possibili stringhe, cioè taaaantissimi tentativi, e usare l’hash come password non porterà a nessun risultato in quanto il server si aspetta una password e quindi tratterà l’hash come tale, producendo di fatto, per il confronto nel database, l’hash dell’hash, che è un nuovo hash totalmente differente dal precedente.