Memorizzi le password con Argon2id, configurato con almeno 19 MiB di memoria, 2 iterazioni e un grado di parallelismo pari a 1, con un salt univoco per ogni password. È la configurazione minima indicata nell'OWASP Password Storage Cheat Sheet. Se il Suo database contiene ancora hash MD5, SHA-1 o privi di salt, può risolvere il problema senza un reset di massa delle password e senza lasciare hash deboli per gli account dormienti.
Cosa usare e quali sono le impostazioni minime
Il cheat sheet indica questi minimi:
| Situazione | Algoritmo | Impostazioni minime |
|---|---|---|
| Preferito | Argon2id | 19 MiB di memoria, 2 iterazioni, parallelismo 1 |
| Argon2id non disponibile | scrypt | parametro di costo 2^17, dimensione del blocco 8, parallelismo 1 |
| Sistemi legacy su bcrypt | bcrypt | work factor pari o superiore a 10, limite di 72 byte per la password |
| Conformità FIPS-140 richiesta | PBKDF2 | 600.000 o più, HMAC-SHA-256 |
Argon2id è la variante principale nella RFC 9106 e ogni implementazione di quel documento deve supportarla. Nella prima metà del primo passaggio sulla memoria si comporta come Argon2i, nel resto come Argon2d.
Il limite di 72 byte di bcrypt
Il cheat sheet fissa un limite di 72 byte per le password con bcrypt. Le fonti non precisano come le singole librerie trattino un input più lungo, quindi verifichi la Sua. Calcoli l'hash di una password composta da 72 caratteri a seguiti da b, poi verifichi 72 caratteri a seguiti da c. Se la verifica ha successo, la Sua libreria tronca l'input in silenzio.
A quel punto limiti la lunghezza delle password nei Suoi form a 72 byte, comunicandolo chiaramente, oppure pianifichi il passaggio ad Argon2id. La RFC 9106 ammette password fino a 2^32-1 byte.
Perché gli hash veloci falliscono
MD5 e SHA-1 sono stati progettati per essere veloci, e SHA-256 non è adatto per lo stesso motivo: consente a un attaccante di fare moltissimi tentativi in poco tempo. L'attaccante calcola l'hash di candidati tratti da elenchi di password trapelate, wordlist o brute force e confronta i risultati con le righe del Suo database. Le GPU e i server cloud a noleggio rendono l'operazione economica.
Un salt univoco costringe l'attaccante a violare gli hash uno alla volta. Inoltre neutralizza le rainbow table e fa sì che password identiche non producano più hash identici. La RFC 9106 raccomanda un salt di 16 byte per l'hashing delle password. Le librerie mature generano e memorizzano il salt per Lei, quindi non lo implementi a mano.
Calibrare il work factor
Non esiste un valore universale. Dipende dal Suo server e dal numero di utenti, e lo si trova per via sperimentale sull'hardware che utilizza. La regola generale è che un singolo hash richieda meno di un secondo.
Esagerare ha un costo. Ogni tentativo di login consuma CPU e un'ondata di tentativi può esaurire le risorse del server. Esegua i benchmark con una concorrenza realistica e scelga un valore sostenibile nei momenti di picco.
Controlli l'unità di misura che la Sua libreria Argon2 si aspetta. La RFC 9106 definisce la dimensione della memoria in kibibyte, mentre il cheat sheet cita i MiB. 19 MiB corrispondono a 19456 KiB, e se passa 19 dove la libreria attende KiB ottiene 19 KiB di memoria. Quell'impostazione funziona ed è molto più debole del previsto.
Il work factor viene di norma memorizzato nell'output dell'hash. Questo aiuta la migrazione, perché al login è possibile vedere con quali parametri è stato creato un determinato hash.
Il pepper come livello aggiuntivo
Un pepper è un segreto condiviso da tutte le password memorizzate e conservato fuori dal database, in un vault dei segreti o in un HSM. È utile quando l'attaccante ottiene solo il database, tramite SQL injection o un backup rubato. Da solo non aggiunge nulla, quindi lo consideri una difesa in profondità.
Il problema è la rotazione. Un pepper compromesso non si può cambiare senza conoscere la password di ciascun utente, quindi sostituirlo impone un reset a tutti coloro che proteggeva. Stabilisca chi è responsabile di quella procedura prima di introdurre un pepper.
Aggiornare i vecchi hash
L'approccio del cheat sheet per aumentare un work factor consiste nell'attendere il successivo accesso dell'utente e poi ricalcolare l'hash della sua password con le nuove impostazioni. Il passaggio da MD5, SHA-1 o hash privi di salt segue la stessa logica, anche se questa estensione è nostra.
- Contrassegni ogni hash memorizzato con il relativo algoritmo, in una colonna separata o tramite il formato dell'hash. Se non è sicuro di cosa contenga la tabella, l'identificatore di hash Le aiuta a riconoscere i formati.
- Al login, verifichi con l'algoritmo utilizzato dall'hash memorizzato.
- In caso di successo, se l'hash è legacy o inferiore ai Suoi parametri attuali, calcoli un nuovo hash Argon2id dalla password inviata, con un salt nuovo.
- Sovrascriva il vecchio valore nella stessa operazione.
ok = verify(row.scheme, row.hash, submitted)
if ok and (row.scheme != "argon2id" or needs_rehash(row.hash)):
row.hash = argon2id_hash(submitted) # fresh salt, current parameters
row.scheme = "argon2id"
save(row)
Account dormienti
Gli utenti che non accedono mai più non vengono mai aggiornati, perciò i loro hash deboli restano nella tabella a tempo indeterminato. Una soluzione è avvolgerli subito. Esegua Argon2id sul valore MD5 o SHA-1 esistente, memorizzi il risultato con un marcatore di schema come argon2id(md5) ed elimini l'hash originale.
Al login calcoli l'hash legacy della password inviata, lo verifichi rispetto al wrapper Argon2id e, in caso di successo, sostituisca il wrapper con un normale hash Argon2id. Registri con precisione come è codificato il valore legacy (esadecimale o byte grezzi), perché una discrepanza fa fallire tutti i login di quello schema. Provi prima il percorso con il wrapper su una copia della tabella.
Il wrapping non rende forte una password debole. Impedisce però che una tabella rubata venga attaccata alla velocità di MD5.
L'alternativa è rimuovere i vecchi hash dopo una data limite e richiedere un reset al successivo accesso, opzione che il cheat sheet descrive come possibile a seconda dell'applicazione. Se la modifica riguarda un codice che non controlla del tutto, il nostro team di sviluppo software sicuro può esaminarla.
Da dove iniziare
- Verifichi la tabella degli utenti: quali algoritmi sono in uso, se esistono i salt e se alcune password sono in chiaro o cifrate in modo reversibile. La cifratura è accettabile solo se deve poter recuperare la password originale, e il cheat sheet raccomanda di evitare questa necessità.
- Scelga Argon2id con almeno 19456 KiB, 2 iterazioni e parallelismo 1, ed esegua il benchmark sull'hardware di produzione finché un hash richiede meno di un secondo.
- Se utilizza bcrypt, esegua il test dei 72 byte descritto sopra e decida tra un limite di lunghezza e il passaggio ad Argon2id.
- Aggiunga al database uno schema con un marcatore dell'algoritmo, modifichi il codice di login in modo che verifichi con il vecchio schema e ricalcoli l'hash in caso di successo.
- Avvolga in Argon2id gli hash legacy rimanenti, oppure fissi una data limite dopo la quale vengono rimossi e diventa necessario un reset.
- Se aggiunge un pepper, lo conservi in un vault dei segreti e metta per iscritto prima la procedura di rotazione e di reset forzato.
