Come può bcrypt avere sali integrati?


617

L'articolo di Coda Hale "Come conservare in modo sicuro una password" afferma che:

bcrypt ha sali integrati per prevenire attacchi da tavolo arcobaleno.

Cita questo documento , che afferma che nell'implementazione di OpenBSD di bcrypt:

OpenBSD genera il sale bcrypt a 128 bit da un flusso di chiavi arcfour (arc4random (3)), seminato con dati casuali che il kernel raccoglie dai tempi dei dispositivi.

Non capisco come possa funzionare. Nella mia concezione di un sale:

  • Deve essere diverso per ogni password memorizzata, quindi dovrebbe essere generata una tabella arcobaleno separata per ciascuna
  • Deve essere archiviato da qualche parte in modo che sia ripetibile: quando un utente tenta di accedere, prendiamo il loro tentativo di password, ripetiamo la stessa procedura salt-and-hash che abbiamo fatto quando abbiamo archiviato la password originariamente e confrontiamo

Quando sto usando Devise (un gestore di login di Rails) con bcrypt, non c'è colonna salt nel database, quindi sono confuso. Se il sale è casuale e non viene memorizzato da nessuna parte, come possiamo ripetere in modo affidabile il processo di hashing?

In breve, come può bcrypt avere sali integrati ?

Risposte:


789

Questo è bcrypt:

Genera un sale casuale. Un fattore "costo" è stato preconfigurato. Raccogli una password.

Deriva una chiave di crittografia dalla password utilizzando il fattore salt e cost. Usalo per crittografare una stringa ben nota. Archivia il costo, il sale e il testo cifrato. Poiché questi tre elementi hanno una lunghezza nota, è facile concatenarli e archiviarli in un singolo campo, ma essere in grado di dividerli in un secondo momento.

Quando qualcuno tenta di eseguire l'autenticazione, recupera il costo e il sale memorizzati. Deriva una chiave dalla password, dal costo e dal sale di input. Crittografa la stessa stringa ben nota. Se il testo cifrato generato corrisponde al testo cifrato memorizzato, la password corrisponde.

Bcrypt opera in modo molto simile agli schemi più tradizionali basati su algoritmi come PBKDF2. La differenza principale è l'uso di una chiave derivata per crittografare il testo normale noto; altri schemi (ragionevolmente) presuppongono che la funzione di derivazione della chiave sia irreversibile e memorizzano direttamente la chiave derivata.


Memorizzato nel database, un bcrypt"hash" potrebbe assomigliare a questo:

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

In realtà si tratta di tre campi, delimitati da "$":

  • 2aidentifica la bcryptversione dell'algoritmo utilizzata.
  • 10è il fattore di costo; Vengono utilizzate 2 10 iterazioni della funzione di derivazione dei tasti (il che non è abbastanza, comunque. Consiglierei un costo di 12 o più.)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTaè il testo salt e the cifher, concatenato e codificato in una Base-64 modificata. I primi 22 caratteri vengono decodificati in un valore di 16 byte per il salt. I caratteri rimanenti sono testo cifrato da confrontare per l'autenticazione.

Questo esempio è tratto dalla documentazione per l'implementazione del rubino di Coda Hale.


7
Avresti maggiori dettagli sul perché il fattore di costo di 10 non sarebbe sufficiente? In Grails, ho notato che 10 è il valore predefinito per fattore di costo / round di log per bcrypt, quindi potrebbe valere la pena aggiornarlo dato il tuo suggerimento.
pm_labs

57
Il fattore di costo per bcrypt è esponenziale, o meglio, un fattore di costo di 10 significa 2 ^ 10 round (1024), un fattore di costo di 16 significherebbe 2 ^ 16 round (65536). È naturale quindi che occorrerebbero 5-10 secondi. Dovrebbe impiegare circa 64 volte tanto quanto un fattore di costo di 10. Per chiarire altre informazioni errate, la funzione crypt di PHP usa la libreria crypt unix che è implementata in c.
thomasrutter,

3
@TJChambers Esatto; se puoi impostare la password sull'account, sarai in grado di autenticarti. L'hash della password non ha lo scopo di prevenire tale attacco. Ha lo scopo di impedire l'autenticazione di un utente malintenzionato con accesso in sola lettura alla tabella delle password. Ad esempio, si ottiene un nastro di backup con la tabella su di esso.
Erickson,

8
@LobsterMan No, non proprio. Se potessi mantenere un segreto, non utilizzeresti questo approccio, memorizzeresti semplicemente la password. Gli schemi di autenticazione con password si basano sul presupposto che l'attaccante abbia scoperto tutto ciò che conosci. Il sale è lì per richiedere che ogni password venga attaccata individualmente. Lo sforzo computazionale richiesto per testare le password è regolato dalle iterazioni. Se gli utenti scelgono una buona password, saranno sicuri, anche se quando viene rivelato il sale. Nascondere il sale potrebbe aiutare qualcuno con una password errata in alcuni casi, ma prima lavorerei sulla qualità della password.
Erickson,

1
@NLV È una stringa definita nella specifica bcrypt:"OrpheanBeholderScryDoubt"
erickson

182

Credo che quella frase avrebbe dovuto essere formulata come segue:

bcrypt ha sali incorporati negli hash generati per prevenire attacchi da tavolo arcobaleno.

L' bcryptutilità stessa non sembra mantenere un elenco di sali. Piuttosto, i sali vengono generati casualmente e aggiunti all'output della funzione in modo che vengano ricordati in seguito (secondo l'implementazione Java dibcrypt ). Detto in altro modo, l '"hash" generato da bcryptnon è solo l'hash. Piuttosto, è l'hash e il sale concatenati.


20
OK, quindi mi iscrivo a un sito e scelgo la password "pippo". Bcryptaggiunge un salt casuale di "akd2! *", risultante in "fooakd2! *", che viene cancellato e memorizzato. Successivamente, provo ad accedere con la password "bar". Per vedere se sono corretto, è necessario hash "barakd2! *". Se il sale è stato generato in modo casuale per cominciare, come fa ad aggiungerlo nuovamente a "bar" prima di eseguire l'hashing e il confronto?
Nathan Long,

46
@Nathan: bcryptsa come estrarre il sale dall'output generato (che è archiviato nel database). Quando arriva il momento di autenticarsi, bcryptsepara l'output originale nei suoi componenti hash e salt. Il componente salt viene applicato alla password in arrivo digitata dall'utente.
Adam Paynter,

22
Per rispondere al commento di Nathan Long, un buon modo di pensare a questo è che i sali non sono fatti per essere segreti. Questo è il motivo per cui il sale è incluso nell'output della funzione bcrypt come una delle risposte indicate sopra. Il sale è lì per impedire le tabelle arcobaleno, che sono elenchi di password comuni, o solo forza bruta, ecc ... di password diverse ma con hash. Senza sale, l'hash per una password nel database A sarebbe lo stesso di un hash per una password nel database B. Salt semplicemente modifica i valori di hash rendendo più difficile per qualcuno che ha rubato il database per decifrare (unhash) le password.
Joseph Astrahan,

11
@Nathan ma un utente malintenzionato può semplicemente rimuovere i sali noti in tutte le password e quindi creare una tabella con loro?
Oscar

3
Ecco come lo capisco: l'idea è che ogni password abbia un sale unico. Il sale incorporato nell'hash della password, quindi un hacker dovrebbe creare una tabella arcobaleno per ogni password. Ciò richiederebbe un'enorme quantità di tempo per un database moderato. Si tratta di rallentare un attaccante e quindi rendere inutile la forza bruta.
PVermeer,

0

Per rendere le cose ancora più chiare,

Direzione registrazione / login ->

La password + salt è crittografata con una chiave generata da: cost, salt e la password. chiamiamo quel valore crittografato il cipher text. quindi alleghiamo il sale su questo valore e lo codifichiamo usando base64. allegandone il costo e questa è la stringa prodotta da bcrypt:

$2a$COST$BASE64

Questo valore viene eventualmente memorizzato.

Cosa dovrebbe fare l'aggressore per trovare la password? (altra direzione <-)

Nel caso in cui l'attaccante ottenga il controllo sul DB, l'attaccante decodificherà facilmente il valore base64 e quindi sarà in grado di vedere il sale. il sale non è segreto. anche se è casuale. Quindi dovrà decifrare il file cipher text.

Ciò che è più importante: non esiste alcun hash in questo processo, piuttosto una crittografia costosa della CPU: la decrittografia. quindi le tabelle arcobaleno sono meno rilevanti qui.


-2

Questo è tratto dalla documentazione dell'interfaccia PasswordEncoder di Spring Security,

 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

Ciò significa che sarà necessario abbinare rawPassword a cui l'utente inserirà nuovamente al successivo accesso e lo abbinerà alla password codificata Bcrypt che viene memorizzata nel database durante il precedente accesso / registrazione.


Questo non risponde affatto alla domanda ... Non dice nulla su come bcrypt possa avere sali
integrati
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.