Un metodo che potrebbe essere utilizzato sarebbe quello di generare "errori di battitura accettabili" al momento della registrazione della password iniziale, quindi di memorizzare gli hash di tutti questi. Ci sono alcuni problemi con questo: si aumenta il tempo richiesto per una modifica della password e per la verifica della password, soprattutto se si utilizza un metodo di hashing della password lenta, come di solito raccomandato, e si aumentano i requisiti di archiviazione di un importo potenzialmente variabile. / p>
Supponiamo che la password utilizzata sia "Password1!" e che "errori di battitura accettabili" siano il caso di singole lettere (o la presenza di caratteri appropriati dalla pressione di Maiusc e un numero), lo scambio di caratteri adiacenti e la mancanza di un singola istanza di un carattere duplicato (questi non sono gli unici errori di battitura possibili, ma dai miei refusi, sono piuttosto facili da fare!).
Ciò significa che tutti i seguenti sono accettabili:
Password1!
aPssword1!
Psasword1!
Password1! [transposing "s" and "s"]
Paswsord1!
Passowrd1!
Passwrod1!
Passwodr1!
Passwor1d!
Password!1
password1!
PAssword1!
PaSsword1!
PasSword1!
PassWord1!
PasswOrd1!
PasswoRd1!
PassworD1!
Password!!
Password11
Pasword1!
Dato qualsiasi algoritmo di password ragionevole (o MD5), questi avranno tutti hash non collegati:
2b4ae288a819f2bcf8e290332c838148
c435f7c0de60f0f69bce9f9a671e748a
8aed93fca5d9b2416c51fee36b03bc6b
9fbad358027d70c0db81fc23ab483c3c
dbf220c136f6b1f27c30997090da4697
c36fc47e48c2a52e450cd06f60bbd3bf
Per verificare una password in questo caso, si hash l'input e si controllano tutti i valori possibili. Puoi anche salare l'input a livello di account e devi solo calcolare un hash. C'è un difetto però.
Conoscere tutti questi hash in realtà non aiuta direttamente un utente malintenzionato, ma può applicare le stesse regole che hai fatto a qualsiasi elenco di password che hanno, e se uno degli hash corrisponde, ottengono l'accesso all'account - questo si applica se usi anche un sale specifico per l'account. Il compromesso per la velocità di accesso li aiuta anche.
Fortunatamente, è abbastanza facile difendersi da questo, con un sale specifico per l'hash. Se usi la maggior parte delle implementazioni di bcrypt, ottieni questo gratuitamente:
Password1!:$2a$04$GgLXwKnxLmnLV/UUtbYahuT9L8R.8/SoKAnRKZUyCuEEgfrX5ITLm
password1!:$2a$04$5Ol8psikd7h0Gt/ZWtQAve0PdA/LO4oub/0JMGC5AA/Rsup/3SBbG
Ora devono provare tutte le modifiche su ogni hash memorizzato. A seconda di come memorizzi le tue password, potrebbero essere in grado di ottimizzare le varianti che tentano contro ogni hash, ma poiché non sanno se la password corretta è "Password1!" o "pAssword1!", c'è il rischio di perdere le cose se lo fanno. Tuttavia, quando qualcuno vuole accedere, devi fare lo stesso.
Questo è il trade-off - se usi un metodo di hashing che richiede 100ms per calcolare, e devi calcolare 1 valore, ci vorranno 100ms per controllare. Se è necessario controllare 10 versioni, ci vorranno 1s di tempo di elaborazione. Se esegui i controlli uno per uno, si ottiene un problema di temporizzazione: risposte rapide indicano che la password originale è stata trovata, quelle più lente significano che ha un refuso. Se li fai in parallelo, hai aumentato i requisiti di elaborazione per il tuo sistema.
Usando solo l'elenco sopra di "errori accettabili", ottieni un numero variabile di potenziali password. Per "Password1!", Significa che stai memorizzando 21 hash, uno dei quali è un duplicato della password originale. Se si richiede un output di tempo costante durante l'accesso al sistema (questa è una buona cosa), è necessario essere in grado di calcolare tutti questi hash in un dato momento, o di ritardare ogni accesso al tempo necessario per calcolare tutte le hash per la password più lunga che supporti. Se non lo fai, hai creato un oracolo per la lunghezza della password.
Esistono metodi di hashing che consentono a input simili di provocare hash simili, ma questi non tendono ad avere proprietà desiderabili per le password di hashing. Sono generalmente ottimizzati per trovare parti simili di grandi strutture di dati, quindi sono ad alta velocità, il che significa che un gran numero di potenziali password può essere provato rapidamente. Essi, per definizione, non hanno un effetto valanghe, il che significa che un potenziale attacco potrebbe provare password comuni, quindi scegliere l'hash "più vicino" a quelli trovati per ulteriori mutazioni. Se un hash di uscita da una mutazione è "più vicino" a quelli memorizzati, anche l'input è più vicino. Con un hash crittografico, anche veloce, la modifica di un singolo carattere nell'input dovrebbe cambiare la maggior parte dell'output. Non c'è un concetto di "più vicino" in termini di output, quindi un attaccante non può fare meglio dei cambiamenti casuali, sperando di ottenere una corrispondenza.
Se si evita completamente il problema di hashing e si scende lungo la rotta HSM, potrebbe essere possibile avere un HSM che memorizza le password in testo non crittografato in modo irrecuperabile e che potrebbe produrre risposte di "originale", "errore di battitura" e "no" usando metodi di confronto classici. Questo potrebbe essere accettabile se hai permesso ad alcune azioni di accedere agli utenti, ma poi hai richiesto la password corretta per le operazioni ad alto rischio (ad esempio cambiando la password), ma non è probabile che sia economicamente conveniente per la maggior parte dei provider.
È certamente possibile, ma ci sono molti potenziali problemi nel farlo e non è chiaro se i vantaggi di UX giustifichino lo sforzo. Probabilmente sarebbe molto più facile incoraggiare l'uso delle applicazioni di gestione password, poiché eviteranno il rischio di errori di battitura in molti casi!