Quando si memorizzano le password dell'utente che è necessario verificare (ma non utilizzare come testo normale) lo stato attuale della tecnica è:
- Hash la password
- Utilizza un sale
- Utilizza una funzione hash lenta - bcrypt, scrypt, ecc.
Fornisce la migliore protezione possibile contro un utente malintenzionato che ha rubato il database delle password. Non risolve altri problemi come phishing, malware, riutilizzo delle password, ecc.
Ma c'è un problema rimanente: la lenta funzione hash può consentire un attacco denial of service . Una singola richiesta brucia molta CPU, il che rende possibile un DOS con un numero relativamente piccolo di richieste simultanee, rendendo difficile l'uso di difese come la limitazione IP.
Dato il miglioramento delle prestazioni di JavaScript nei browser, potrebbe ora avere senso farlo nel browser. Presumo qui che il sito stia utilizzando SSL, quindi il JavaScript viene consegnato in modo sicuro. Se non stai utilizzando SSL, è improbabile che l'utilizzo di una funzione hash lenta sia una priorità per te. Esiste almeno una implementazione JavaScript di bcrypt. Ma usando questo in un modo semplice introdurrebbe due problemi:
- Il client deve recuperare il sale dal server. Questo introduce la latenza all'accesso e, a meno che non si prenda cura, può rivelare se esiste un particolare account utente.
- Se l'hashing viene eseguito esclusivamente sul client, i vantaggi dell'archiviazione degli hash vengono persi. All'attaccante che ha rubato gli hash delle password può semplicemente accedere utilizzando gli hash.
Tuttavia, penso che ci siano soluzioni accettabili per entrambi questi problemi:
- Il sale può essere generato come hash (server_salt + user_name) - dove server_salt è un numero casuale che è univoco per il server, pubblico, e lo stesso per tutti gli utenti. L'hash risultante sembra avere le proprietà richieste di un sale.
- Il server deve eseguire una singola operazione di hash veloce sull'hash che riceve. Ad esempio: il server memorizza SHA-256 (bcrypt (salt, password)). Il client invia bcrypt (salt, password), quindi il server applica SHA-256 e controlla l'hash. Questo NON consente a un utente malintenzionato di condurre un attacco brute offline veloce. Possono fare una forza bruta veloce di SHA-256 (password) perché la password ha una quantità limitata di entropia - 2 ^ 50 o 2 ^ 60 o giù di lì. Ma un bcrypt a 128 bit (sale, password) ha entropia o 2 ^ 128, quindi non possono facilmente forzarlo.
Quindi, questo è un approccio ragionevole e sicuro?
Sono consapevole del consiglio generale di "non tirare la tua cripto". Tuttavia, in questo caso, sto tentando di risolvere un problema che non è risolto dalla crittografia predefinita. Per alcune credibilità di base, questo è stato osservato da John Steven ( un esperto riconosciuto nel campo) con esito positivo da un'analisi "breve".