HMAC - Perché non HMAC per l'archiviazione delle password?

44

Nota bene: Sono consapevole che buona risposta per proteggere l'archiviazione delle password è scrypt o bcrypt . Questa domanda non è per l'implementazione nel software attuale, è per mia comprensione.

Diciamo che Joe Programmer ha il compito di memorizzare in modo sicuro le password degli utenti finali in un database per un'applicazione web; o memorizzazione di password su disco per accessi a un software. Molto probabilmente:

  1. Ottieni $password dall'utente finale.
  2. Crea $nonce come valore casuale di 64 o 128 bit di grandi dimensioni.
  3. Crea $hash = SHA256($nonce$password) e salva $nonce insieme a $hash nel database.

Prima domanda:

Perché il seguente non è sostanzialmente migliore di quello sopra?

  1. Crea $long_string una volta e una sola volta. Memorizzalo come una costante nel codice dell'applicazione. $long_string potrebbe f.x. essere 2 kilobyte di caratteri casuali.
  2. Ottieni $password dall'utente finale.
  3. Crea $mac = HMAC-SHA256($long_string)[$password] (cioè crea un MAC utilizzando la password dell'utente finale come chiave) e memorizza questo $mac nel database.

Immagino che l'HMAC abbia i seguenti vantaggi?

  • Le collisioni sono meno frequenti?
  • È computazionalmente un po 'più costoso di semplice hashing? (Ma non ovunque vicino a scrypt, ovviamente.)
  • Per riuscire con un attacco di forza bruta entro un tempo ragionevole, e l'attaccante dovrebbe avere accesso a due cose: 1) il database, dove $mac è memorizzato, e < em> 2) il codice dell'applicazione, in cui è memorizzato il $long_string originale. È meglio di una funzione hash, in cui l'hacker deve solo accedere al database?

Ma ancora, nessuno sembra suggerire di usare un HMAC, quindi devo essere frainteso qualcosa?

Seconda domanda:

Quali sarebbero le implicazioni dell'aggiunta di un valore salino $nonce essere?

  1. Crea $long_string una volta e una sola volta. Salva questo come costante nel codice dell'applicazione.
  2. Ottieni $password dall'utente finale.
  3. Crea $nonce come valore casuale di circa 128 bit di grandi dimensioni.
  4. Crea $mac = HMAC-SHA256($long_string)[$nonce$password] e salva $nonce e $mac nel database.
posta Jesper Mortensen 19.04.2011 - 14:09
fonte

2 risposte

33

Il punto del sale è prevenire la condivisione dei costi degli attacchi: se un utente malintenzionato vuole attaccare due password, dovrebbe essere due volte più costoso dell'attacco di una password.

Con la tua proposta (la tua "domanda 1"), due utenti con la stessa password finiranno per utilizzare lo stesso MAC. Se un utente malintenzionato ha accesso in lettura al database, può "provare" le password (ricalcando il MAC) e cercare il database per una corrispondenza. Può quindi attaccare tutte le password in parallelo, al costo di attaccarne una. Se long_string è una costante hardcoded nel codice sorgente dell'applicazione, tutte le istanze installate dell'applicazione condividono questa costante e diventa utile (per l'utente malintenzionato) precomporre un grande dizionario di coppie password-to-MAC, note anche come "un tavolo arcobaleno".

Con un nonce (la tua "domanda 2") eviti la condivisione dei costi. Il nonce è generalmente noto come "sale". Il tuo long_string e l'uso di HMAC non ti compri molto qui (e non stai usando HMAC per quello per cui è stato progettato, a proposito, quindi sei su fondamenta traballanti, in termini crittografici). Usare una salina è un'ottima idea (beh, non usare una salina è una pessima idea, almeno) ma fa solo metà del lavoro. Devi anche avere una procedura di hashing slow . Il punto qui è che il sale previene la condivisione dei costi, ma non impedisce di attaccare una singola password. Attaccare una password significa provare le password possibili fino a una corrispondenza (è l'attacco del dizionario), e, data l'immaginazione dell'utente medio, gli attacchi al dizionario tendono a funzionare: le persone semplicemente amano usando password che possono essere indovinato. La soluzione alternativa consiste nell'utilizzare un processo di hashing che è intrinsecamente lento, di solito ripetendo la funzione di hash alcune migliaia di volte. L'idea è di rendere la verifica della password più costosa: avere un utente che aspetta 1 ms invece di 1μs non è un problema (l'utente non lo noterà), ma renderà anche il dizionario un attacco 1000 volte più costoso. Il tuo long_string può essere usato per quello, a condizione che sia molto lungo (non 2 kilobyte, piuttosto 20 megabyte).

È possibile utilizzare HMAC al posto di una funzione di hash raw per rafforzare un sistema di verifica della password, ma in una configurazione diversa. Dato un sistema che controlla le password con sali e funzioni hash iterate, è possibile sostituire la funzione hash con HMAC, usando una chiave segreta K . Questo impedisce attacchi di dizionario offline finché puoi mantenere K segreto. Mantenere un valore segreto non è facile, ma è ancora più semplice mantenere un K segreto a 128 bit di un database completo.

    
risposta data 19.04.2011 - 15:00
fonte
3

HMAC non ti compra molto qui, anche se suppongo che agisca come una funzione di hash sostituibile (sostituibile cambiando la chiave). Comunque sembra proprio eccessivo qui.

Tuttavia, il primo schema che proponi sopra fallisce in modo catastrofico se $ long_string diventa noto a un utente malintenzionato, cosa che probabilmente succederà dal momento che probabilmente il codice non è considerato segreto (ed è generalmente una cattiva pratica affidarsi alla segretezza del codice comunque ).

Dovresti utilizzare il secondo schema dato che $ nonce è necessario per proteggere dagli attacchi precomputi

    
risposta data 19.04.2011 - 14:54
fonte

Leggi altre domande sui tag