Perché è sempre "HASH (salt + password)" che consigliamo?

21

Navigando su questo sito, molti forum, articoli online, c'è sempre un modo specifico che suggeriamo di memorizzare un hash della password:

function (salt, pass) {
   return ( StrongHash(salt + pass) )
}

Ma perché questo modo esatto ? Perché non stiamo suggerendo di fare questo?

function (salt, pass) {
   return (StrongHash(( StrongHash(salt) + StrongHash(pass) ))
}

O anche qualcosa di simile?

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data += StrongHash(salt + data)
   }
   return (data)
}

O qualche altra pazza combinazione? Perché stiamo specificamente dicendo hash la concatenazione del sale grezzo e la password raw? L'hash di entrambi i hash sembra essere un'alternativa ad alta entropia, così come hashing 1000 volte secondo il mio terzo esempio. Perché non eliminiamo il primo qualche altra volta per l'entropia?

Cosa c'è di così sorprendente nel primo modo?

Su richiesta, esempi di questo:

  1. link
  2. Password Hashing aggiungi sale + pepe o sale abbastanza?
  3. Stretching di un hash, molte iterazioni rispetto a input più lunghi stringa
  4. link
  5. link
  6. link
  7. link
  8. link
  9. link
  10. link
posta Incognito 15.06.2011 - 16:22
fonte

2 risposte

41

In realtà, "noi" stiamo non raccomandando ciò che mostri. I soliti consigli sono PBKDF2 , bcrypt o SHA-2 basato su critto Unix attualmente utilizzato in Linux.

Se la funzione di hash che usi è un oracolo casuale allora non importa in che modo si immettono il sale e la password; importa solo il tempo che serve per elaborare il sale e la password, e vogliamo che il tempo sia lungo, così da scoraggiare le ricerche nel dizionario; quindi l'uso di più iterazioni. Tuttavia , essere un oracolo casuale perfetto è una proprietà difficile per una funzione hash; non è implicito dalle solite proprietà di sicurezza che devono garantire le funzioni di hash sicuro (resistenza alle collisioni e alle preimmagini) ed è noto che alcune funzioni di hash ampiamente utilizzate non sono oracoli casuali; per esempio. le funzioni SHA-2 soffrono del cosiddetto "attacco di estensione della lunghezza", che non le rende meno sicure, ma implica una certa attenzione quando si utilizza la funzione in schemi di hashing di password funky. PBKDF2 è spesso usato con HMAC per questo motivo.

Sei caldamente incoraggiato non a sentirti creativo con schemi di hashing delle password o crittografia in generale. La sicurezza si basa su dettagli che sono sottili e che non puoi testare da solo (durante i test, una funzione non sicura funziona altrettanto bene di una sicura).

    
risposta data 15.06.2011 - 16:52
fonte
9

Sulle due proposte -

function (salt, pass) {    return
    (StrongHash( StrongHash(salt) + StrongHash(pass) ) 
}

Non ci sono bonus qui. Un hash rende le informazioni in qualcosa di casuale. Quindi, nel primo passaggio, hai creato due pezzi di dati in due stringhe casuali e poi hai combinato due stringhe casuali. Perché? La sicurezza attraverso l'oscurità non offre alcun vantaggio. Gli elementi critici della soluzione generalmente proposta sono:

  • abbina sali e amp; password in modo che il sale possa fornire un fattore di caos aggiunto per la creazione dell'hash di una password
  • hash unidirezionale conglomerato per creare una stringa apparentemente casuale.

Non puoi essere più casuale che casuale - e con sicurezza è bene evitare il lavoro che non ha uno scopo.

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data += StrongHash(salt + data)
   }
   return (data)
}

La prima cosa che sta succedendo qui è che i dati sono dati il sale e la password. Quindi il risultato sarà:

<Salt><Password><randomString0><randomString1>....<randomString999>

<Salt> = the salt in cleartext
<Password> = the password in cleartext
<randomString> = a series of different random strings.

Il codice come scritto mostra solo la password, quindi tutte le stringhe casuali non servono a nulla.

Una soluzione a questo problema potrebbe essere:

function (salt, pass) {
   var data = salt + pass;
   for (i=0;i < 1000; i++ {
       data = StrongHash(salt + data)
   }
   return (data)
}

Annota la rimozione di + = e passa a un semplice compito. È un piccolo cambiamento, ma significa che ora i tuoi dati finali sono una singola stringa casuale della lunghezza che il tuo algoritmo di hash produce.

Probabilmente va bene dal punto di vista della sicurezza, ma non c'è, ancora una volta, un vero miglioramento rispetto alla semplice versione originale. La ripetizione di molti hash ricorsivi non aggiunge alcuna sicurezza: il tuo primo passaggio con un algoritmo hash dovrebbe produrre un risultato casuale. L'hashing della stessa cosa più e più volte non fa nulla nel migliore dei casi, e il caso peggiore potrebbe finire per ridurre il valore dell'algoritmo hash.

Il primo modo offre un vantaggio molto significativo: il principale dei KISS. Keep It Simple. Quando la ripetizione della funzione non offre alcun vantaggio, non c'è motivo di rendere la tua logica più complicata, più lunga da elaborare, più aperta all'errore e più difficile da eseguire il debug.

Inoltre, con la crittografia, tutti gli algoritmi dovrebbero venire con un manuale utente che riempirebbe il tuo cubicolo medio. La discussione sulle chiavi deboli, i problemi con la ripetizione, l'esposizione e altri dibattiti di input / output matematici manterranno i matematici riforniti di argomenti di tesi per il resto dell'eternità. Finché non c'è un algoritmo specifico in gioco, è difficile discutere delle reali ripercussioni, ma è generalmente buona norma lasciare le ripetizioni e le permutazioni all'algoritmo piuttosto che cercare di dare una mano. Molti algoritmi di hash hanno già cicli di ripetizione e ricorsione che indicano che l'utente non ha motivo di fare di più.

    
risposta data 15.06.2011 - 18:48
fonte

Leggi altre domande sui tag