Un pizzico di sale con le funzioni Hash

Qualcuno di voi mi dirà: "ancora?"
Sì sì ancora! Con mio grande stupore questo argomento non è ancora ben conosciuto e compreso nella comunità dei developer che, pur avendo capito che le password non si scrivono in chiaro ma conviene comunque hasharle con una funzione one-way, si dimenticano (o peggio non sanno) che nel caso di hash per autenticazioni devono aggiungere il cosiddetto SALT (sale).
Il concetto di SALT è ben vecchio e consiste nell'aggiungere una stringa binaria casuale di lunghezza prefissata e sufficientemente lunga alla password in chiaro, per poi passare il risultato ad una funzione hash (MD5, SHA1, etc.). Questo componendo N volte la funzione di Hash. Poi, nel passo finale, aggiungere il SALT e il numero di iterazioni N in chiaro.
Sì sì ancora! Con mio grande stupore questo argomento non è ancora ben conosciuto e compreso nella comunità dei developer che, pur avendo capito che le password non si scrivono in chiaro ma conviene comunque hasharle con una funzione one-way, si dimenticano (o peggio non sanno) che nel caso di hash per autenticazioni devono aggiungere il cosiddetto SALT (sale).
Il concetto di SALT è ben vecchio e consiste nell'aggiungere una stringa binaria casuale di lunghezza prefissata e sufficientemente lunga alla password in chiaro, per poi passare il risultato ad una funzione hash (MD5, SHA1, etc.). Questo componendo N volte la funzione di Hash. Poi, nel passo finale, aggiungere il SALT e il numero di iterazioni N in chiaro.
Con una notazione un po' più formale: se H è la funzione di hash prescelta, N il numero di volte che viene applicata, PASSWORD(k) è la k-esima password e SALT(k) è una stringa binaria casuale di lunghezza prefissata (e possibilmente abbastanza lunga) per la k-esima password, allora quello che memorizzeremo nel nostro campo password è il valore SALTED-HASH, dove:
SALTED-HASH := H(H(...(H(PASSWORD(k)+SALT(k))+...)+SALT(k))+SALT(k)) + SALT(k) + N
La determinazione di SALTED-HASH ha un costo O(N). Anche se N fosse 1000 (e il PKCS5 prevede appunto 1000 iterazioni) è comunque un tempo costante impiegato unicamente alla prima registrazione della password.
Quando invece si deve verificare la password immessa dell'utente USERNAME, si scorre la tabella per trovare il dato identificativo USERNAME (k-esimo) e si ricavano la corrispondente stringa SALTED-HASH, N e SALT(k) (questi ultimi due di lunghezza prefissata e in chiaro). Si ricalcola quindi la funzione SALTED-HASH a partire dalla password immessa dall'utente, verificando se vi sia corrispondenza o meno con quella memorizzata. Anche qui il tempo è costante e nell'ordine di O(N) per ogni accesso.
Perché è necessario comporre N volte la funzione hash prescelta con questo dato casuale chiamato SALT?
Per evitare che il file delle password possa essere sottoposto ad attacchi del dizionario, Rainbow Table, o attacchi a forza bruta.
Con un insieme di Hash precalcolati di un dizionario o di un insieme di stringhe, posso facilmente trovare le eventuali corrispondenze tra il mio dizionario hashato (senza salt) e qualche hash nel file delle password. Risalendo così alla password in chiaro.
Inserendo invece il SALT e applicando la composizione della funzione Hash, si introduce un dato casuale per ogni password, che richiederebbe ad un attaccante, sempre per ogni password, di ricalcolare tutti gli hash del dizionario utilizzato per l'attacco. La stessa cosa vale per attacchi a forza bruta o rainbow table. In questo modo il costo computazionale dell'attacco sarebbe quindi molto svantaggioso rendendo l'attacco vano.
In conclusione: aggiungere il SALT e utilizzare la composizione della funzione Hash N volte è un MUST e deve essere considerato un requisito di sicurezza qualora si utilizzi una funzione Hash per autenticare utenze. E comunque non utilizzate più l'MD5, almeno uno SHA1!
Sempre sull'argomento qualche post da Coding Horror più "filosofico":
Ciao Roberto, complimenti per il tuo blog e per i tuoi post sulle funzioni hash. Io sto terminando un paper sull'hashing con php (con licenza creative commons, e che poi andrà su wikibooks). Volevo chiederti: posso utilizzare la foto di questo articolo (HASH con lo sfondo di..sale) per il paper? ovviamente con citazione e ringraziamenti.
RispondiEliminasegnalazionit [at] gmail
Darò una letta alla vostra pubblicazione (e magari ci faccio anche un post ;-))
RispondiEliminaVero, ma anche SHA1 e' vulnerabilissimo :-)
RispondiElimina