Di solito funziona in questo modo:
Supponi che la tua password sia "baseball". Potrei semplicemente archiviarlo grezzo, ma chiunque ottiene il mio database ottiene la password. Così invece ci faccio un hash SHA1 e ottengo questo:
$ echo -n baseball | sha1suma2c901c8c6dea98958c219f6f2d038c44dc5d362
Teoricamente è impossibile invertire un hash SHA1. Ma fai una ricerca su Google su quella stringa esatta e non avrai problemi a recuperare la password originale.
Inoltre, se due utenti nel database hanno la stessa password, allora avranno lo stesso hash SHA1. E se uno di loro ha un suggerimento per la password che dice prova "baseball"
, beh, ora so quali sono entrambe le password degli utenti.
Quindi, prima di eseguirne l'hashing, anteponiamo una stringa univoca. Non un segreto , solo qualcosa di unico. Che ne dici di WquZ012C
. Quindi ora stiamo eseguendo l'hashing della stringa WquZ012Cbaseball
. Il risultato è questo:
c5e635ec235a51e89f6ed7d4857afe58663d54f5
Se cerchi su Google quella stringa non viene visualizzato nulla (tranne forse questo pagina), quindi ora siamo a qualcosa. E se person2 usa anche "baseball" come password, usiamo un salt diverso e otteniamo un hash diverso.
Ovviamente, per testare la tua password, devi sapere qual è il sale. Quindi dobbiamo conservarlo da qualche parte. La maggior parte delle implementazioni lo inseriscono proprio lì con l'hash, di solito con un delimitatore. Prova questo se hai openssl
installato:
[tylerl ~] $ openssl passwd -1Password: baseballVerifying - Password: baseball $ 1 $ oaagVya9 $ NMvf1IyubxEYvrZTRSLgk0
Questo ci fornisce un hash usando la libreria crypt
standard. Quindi il nostro hash è $ 1 $ oaagVya9 $ NMvf1IyubxEYvrZTRSLgk0
: in realtà si tratta di 3 sezioni separate da $
. Sostituirò il delimitatore con uno spazio per renderlo visivamente più chiaro:
$ 1 $ oaagVya9 $ NMvf1IyubxEYvrZTRSLgk0 1 oaagVya9 NMvf1IyubxEYvrZTRSLgk0
- 1 significa "algoritmo numero 1" che è un po 'complicato, ma utilizza MD5. Ce ne sono molti altri che sono molto migliori, ma questo è il nostro esempio.
- oaagVya9 è il nostro sale. Inserito proprio lì con il nostro hash.
- NMvf1IyubxEYvrZTRSLgk0 è la somma MD5 effettiva, codificata in base64.
Se eseguo il processo di nuovo, ottengo un hash completamente diverso con un sale diverso. In questo esempio, ci sono circa 10 14 modi per memorizzare questa password. Tutti questi sono per la password "baseball":
$ 1 $ 9XsNo9.P $ kTPuyvrHqsJJuCci3zLwL. $ 1 $ nLEOCtx6 $ uSnz6PF8q3YuUhB3rLTC3 / $ 1 $ / jZJXTF3zLwL. $ 1 $ nLEOCtx6 $ uSnz6PF8q3YuUhB3rLTC3 / $ 1 $ / jZJXTF8Kb / OqDamf. U $ KR0jkhpeb1sz.UIqvfYOR.
Ma, se specifichi deliberatamente il sale che voglio controllare, ottengo il risultato atteso:
[ tylerl ~] $ openssl passwd -1 -salt oaagVya9Password: baseballVerifying - Password: baseball $ 1 $ oaagVya9 $ NMvf1IyubxEYvrZTRSLgk0
E questo è il test che eseguo per verificare se la password è corretta. Trova l'hash memorizzato per l'utente, trova il salt salvato, riesegui lo stesso hash usando il salt salvato, controlla per vedere se il risultato corrisponde all'hash originale.
Implementing This Yourself
Per essere chiari, questo post non è una guida all'implementazione. Non limitarti a salare il tuo MD5 e chiamarlo buono. Non è abbastanza nell'attuale clima di rischio. Dovrai invece eseguire un processo iterativo che esegue la funzione hash migliaia di volte. Questo è stato spiegato altrove molte volte, quindi non esaminerò il "perché" qui.
Ce ne sono molti ben consolidati e opzioni affidabili per farlo:
crypt : la funzione che ho usato sopra è una variante precedente del meccanismo di hashing delle password crypt
unix integrato in tutti Sistemi operativi Unix / Linux. La versione originale (basata su DES) è terribilmente insicura; non considerarlo nemmeno. Quello che ho mostrato (basato su MD5) è migliore, ma non dovrebbe ancora essere usato oggi. Le variazioni successive, comprese le variazioni SHA-256 e SHA-512, dovrebbero essere ragionevoli. Tutte le varianti recenti implementano più cicli di hash.
-
bcrypt : la versione blowfish di crypt codice> chiamata funzionale di cui sopra. Sfrutta il fatto che blowfish ha un processo di configurazione della chiave molto costoso e utilizza un parametro "cost" che aumenta il tempo di configurazione della chiave di conseguenza.
-
PBKDF2 : ("Funzione di derivazione chiave basata su password versione 2") creata per produrre chiavi crittografiche complesse da semplici password, questa è l'unica funzione qui elencata che ha effettivamente una RFC. Esegue un numero configurabile di round, con ogni round hash la password più il risultato del round precedente. Il primo round utilizza un sale. Vale la pena notare che lo scopo originario previsto è creare chiavi efficaci , non memorizzare password , ma la sovrapposizione degli obiettivi rende questa soluzione affidabile anche qui. Se non hai librerie disponibili e sei costretto a implementare qualcosa da zero, questa è l'opzione più semplice e meglio documentata. Tuttavia, ovviamente, utilizzare una libreria ben controllata è sempre la cosa migliore.
-
scrypt : un sistema progettato di recente specificamente per essere difficile da implementare su hardware dedicato. Oltre a richiedere più round di una funzione di hashing, scrypt ha anche uno stato di memoria di lavoro molto ampio, in modo da aumentare il requisito di RAM per le implementazioni. Sebbene sia molto nuovo e per lo più non provato, sembra sicuro almeno quanto gli altri, e forse il più sicuro di tutti.