Quando ti registri a un servizio online, la tua password dovrebbe essere conservata in una forma che nemmeno il gestore del servizio possa leggere. Non cifrata, perché ciò che è cifrato si può decifrare con la chiave, ma trasformata con una funzione di hashing per password. La differenza tra farlo bene e farlo male emerge il giorno in cui il database viene sottratto: in un caso le password restano protette, nell'altro vengono recuperate in poche ore.
Perché non basta un hash qualsiasi
Una funzione hash è a senso unico: dall'impronta non si risale all'originale. Ma un attaccante non ha bisogno di "invertire" la funzione. Gli basta indovinare: prende una password candidata, ne calcola l'hash e lo confronta con quelli rubati. Se coincidono, ha trovato la password.
Gli hash generici come SHA-256 sono progettati per essere velocissimi. Su schede grafiche moderne se ne calcolano miliardi al secondo. Con un dizionario di password comuni, varianti e combinazioni, gran parte delle password reali cade rapidamente.
Il sale: ogni password diventa unica
Il primo accorgimento è il sale (salt): un valore casuale, diverso per ogni utente, che viene unito alla password prima del calcolo e salvato insieme all'hash.
Il sale risolve due problemi:
- due utenti con la stessa password hanno hash diversi, quindi non si può capire chi condivide la stessa password;
- le tabelle precalcolate, come le cosiddette tabelle arcobaleno, diventano inutili, perché andrebbero ricostruite da capo per ogni singolo sale.
Il sale non è segreto: serve solo a rendere unico ogni calcolo. Non rallenta però l'attacco mirato a una singola password.
La lentezza voluta: il fattore di costo
Il secondo accorgimento è rendere il calcolo deliberatamente lento e costoso. Se un utente legittimo deve aspettare un decimo di secondo al momento dell'accesso, non se ne accorge. Un attaccante che deve provare miliardi di combinazioni, invece, vede il suo lavoro moltiplicarsi enormemente.
Le funzioni per password hanno un parametro di costo regolabile, da aumentare nel tempo man mano che l'hardware diventa più veloce.
Le funzioni principali
PBKDF2
Ripete un hash, tipicamente HMAC-SHA256, un numero elevato di volte. È standardizzato e diffuso, ma ha un limite: richiede pochissima memoria, quindi si parallelizza bene su schede grafiche e hardware dedicato. Va usato con un numero di iterazioni molto alto.
bcrypt
Progettato alla fine degli anni Novanta, è stato per molto tempo la scelta predefinita in molti framework. Il suo fattore di costo è esponenziale: ogni incremento di uno raddoppia il tempo di calcolo. Ha una particolarità da conoscere: considera solo i primi 72 byte della password, e ciò che segue viene ignorato.
scrypt
Introduce un'idea importante: essere costoso in memoria, oltre che in tempo. Per calcolare un hash serve una quantità significativa di RAM. Questo rende molto più difficile e costoso costruire hardware specializzato che esegua milioni di tentativi in parallelo.
Argon2
Ha vinto nel 2015 la Password Hashing Competition, una selezione pubblica pensata appositamente per individuare un nuovo standard. Permette di regolare separatamente tempo, memoria e grado di parallelismo. Esistono tre varianti; quella generalmente raccomandata per le password è Argon2id, che combina resistenza agli attacchi con hardware dedicato e a certi attacchi basati sull'osservazione degli accessi in memoria.
Un confronto rapido
| Funzione | Costo in memoria | Note |
|---|---|---|
| PBKDF2 | Basso | Standard diffuso, richiede molte iterazioni |
| bcrypt | Basso e fisso | Collaudato, limite di 72 byte |
| scrypt | Alto | Buona resistenza all'hardware dedicato |
| Argon2id | Configurabile | Scelta consigliata per i nuovi sistemi |
Il pepe: un segreto in più
Alcuni sistemi aggiungono un pepe (pepper): un valore segreto, uguale per tutti, che non viene salvato nel database ma in un luogo separato, per esempio un modulo hardware o la configurazione del server. Se viene sottratto solo il database, l'attaccante non può nemmeno iniziare a provare le password. Il pepe è un rinforzo, non un sostituto di sale e lentezza.
Dalla password alla chiave
Le stesse funzioni servono anche per derivare una chiave di cifratura da una password, per esempio quando proteggi un archivio, un gestore di password o la chiave privata di un certificato. Il principio è identico: rendere costoso ogni tentativo di indovinare. Un archivio cifrato con AES-256 ma con una chiave derivata in modo veloce da una password debole è protetto solo quanto quella password.
Cosa conta davvero per l'utente
Anche la migliore funzione di hashing non salva una password come "123456" o il nome del proprio animale domestico seguito dall'anno di nascita: sono tra i primi tentativi di qualsiasi attacco. Una password lunga, generata casualmente e conservata in un gestore di password, unita all'autenticazione a più fattori, rende quasi irrilevante il furto del database di un singolo servizio.
In sintesi
- Le password si conservano con funzioni di hashing dedicate, non con cifratura né con hash veloci.
- Il sale rende unico ogni hash e neutralizza le tabelle precalcolate.
- Il fattore di costo rende ogni tentativo lento e va aumentato nel tempo.
- Argon2id è la scelta consigliata; scrypt, bcrypt e PBKDF2 restano accettabili se ben configurati.
- Le stesse funzioni servono a derivare chiavi di cifratura da una password.