Il password hashing è la pratica di trasformare una password in chiaro in un’impronta crittografica prima di memorizzarla, in modo che in caso di violazione del database le password originali non siano immediatamente recuperabili. Non tutte le funzioni hash sono adatte a questo scopo: le funzioni crittografiche generali come SHA-256 o MD5 sono progettate per essere veloci — una proprietà desiderabile per il calcolo di integrità dei file, ma disastrosa per la protezione delle password, perché permette di eseguire miliardi di tentativi al secondo con hardware comune. I moderni algoritmi di password hashing risolvono questo problema essendo deliberatamente lenti e costosi in memoria.
Perché SHA-256 non va usato per le password
SHA-256 su GPU moderna: ~10 miliardi di hash al secondo. Una password di 8 caratteri alfanumerici ha circa combinazioni — esauribili in ore. Un database di password hashate con SHA-256 (o peggio, MD5) dopo un breach è effettivamente compromesso nella maggior parte dei casi in pochi giorni con hardware standard e dizionari di password comuni.
Il secondo problema è la mancanza di salt: se due utenti hanno la stessa password, producono lo stesso hash. Le rainbow table — database precalcolati di hash di password comuni — permettono di invertire l’hash in tempo costante. Il salt (valore casuale aggiunto alla password prima dell’hash) elimina questo vettore rendendo ogni hash unico.
bcrypt
Progettato da Niels Provos e David Mazières nel 1999, bcrypt è basato sull’algoritmo di cifratura Blowfish. Introduce un parametro di costo (cost factor) che determina il numero di iterazioni: cost=12 esegue round. Aumentare il cost factor di 1 raddoppia il tempo di calcolo — permette di mantenere la resistenza nel tempo all’aumentare della potenza computazionale disponibile.
Il salt (16 byte casuali) è incorporato nell’output insieme al cost factor e all’hash, in un formato autocontenuto:
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/ggDoHBiQ.EfF/U1Xi
↑ ↑ ←────── salt (22 char Base64) ──────→←── hash ────→
versione cost
Limite di bcrypt: tronca la password a 72 byte — password più lunghe non aggiungono sicurezza. Su GPU moderne rimane ragionevolmente resistente, ma la sua struttura non è memory-hard.
scrypt
Progettato da Colin Percival nel 2009 per essere sia time-hard sia memory-hard: richiede una quantità significativa di RAM per essere calcolato, rendendo gli attacchi con ASIC o GPU molto meno efficaci perché questi dispositivi hanno memoria limitata per core. I parametri sono N (costo CPU/memoria), r (fattore di blocco), p (parallelizzazione). Adottato da Litecoin come algoritmo di proof-of-work.
Argon2
Vincitore della Password Hashing Competition (2015), Argon2 è l’algoritmo raccomandato da OWASP e dall’IETF (RFC 9106) per le nuove applicazioni. Esistono tre varianti:
- Argon2d: massima resistenza agli attacchi GPU, vulnerabile a side-channel
- Argon2i: resistente a side-channel, leggermente meno resistente alla GPU
- Argon2id: ibrido, combinazione dei due — raccomandata per la maggior parte degli usi
I parametri configurabili sono: m (memoria in KiB), t (iterazioni), p (parallelismo). OWASP raccomanda come minimo m=19456 (19 MiB), t=2, p=1.
Raccomandazioni pratiche
| Scenario | Algoritmo raccomandato |
|---|---|
| Nuova applicazione | Argon2id |
| Sistemi legacy che supportano solo bcrypt | bcrypt con cost ≥ 12 |
| Sistemi con vincoli di memoria | scrypt o bcrypt |
| Mai usare | MD5, SHA-1, SHA-256/512 senza KDF, cifratura reversibile |
Il parametro di costo va calibrato in modo che l’hash di una singola password richieda ~100–300 ms sull’hardware di produzione — abbastanza da rendere il brute force impraticabile, abbastanza poco da non degradare l’esperienza utente in login normali.
In caso di breach, la lentezza dell’algoritmo è l’unico fattore che guadagna tempo: anche con Argon2id a parametri robusti, password brevi o comuni sono recuperabili. La prima linea di difesa rimane imporre password lunghe o passphrase.