it-swarm.dev

Perché gli hash salati sono più sicuri per l'archiviazione delle password?

So che ci sono molte discussioni sugli hash salati e capisco che lo scopo è rendere impossibile la creazione di una tabella arcobaleno di tutti gli hash possibili (in genere fino a 7 caratteri).

La mia comprensione è che i valori salati casuali sono semplicemente concatenati all'hash della password. Perché una tabella Rainbow non può essere utilizzata contro l'hash della password e ignorare i primi X bit noti come hash salt casuale?

pdate

Grazie per le risposte Immagino che funzioni, la directory (LDAP, ecc.) Deve memorizzare un salt specifico per ogni utente, o sembra che il salt verrebbe "perso" e l'autenticazione non potrebbe mai avvenire.

250
Tsyras

In genere funziona così:

Di 'che la tua password è "baseball". Potrei semplicemente archiviarlo grezzo, ma chiunque ottenga il mio database ottiene la password. Quindi invece faccio un hash SHA1 su di esso e ottengo questo:

$ echo -n baseball | sha1sum
a2c901c8c6dea98958c219f6f2d038c44dc5d362

Teoricamente è impossibile invertire un hash SHA1. Ma vai na ricerca su google su quella stringa esatta , e non avrai problemi a recuperare la password originale.

Inoltre, se due utenti nel database hanno la stessa password, avranno lo stesso hash SHA1. E se uno di essi ha un suggerimento password che dice try "baseball" - bene ora so cosa sono entrambi le password degli utenti.

Quindi, prima di eseguire l'hash, anteponiamo una stringa univoca. Not a secret, solo qualcosa di unico. Che ne dite di WquZ012C. Quindi ora eseguiamo l'hashing della stringa WquZ012Cbaseball. Questo l'hash:

c5e635ec235a51e89f6ed7d4857afe58663d54f5

Cercando su Google quella stringa non viene visualizzato nulla (tranne forse this page), quindi ora siamo su qualcosa. E se person2 usa anche "baseball" come password, usiamo un sale diverso e otteniamo un hash diverso.

Naturalmente, per testare la tua password, devi sapere qual è il sale. Quindi dobbiamo conservarlo da qualche parte. La maggior parte delle implementazioni lo affronta proprio lì con l'hash, di solito con qualche delimitatore. Prova questo se hai openssl installato:

[tylerl ~]$ openssl passwd -1
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

Questo ci dà un hash usando la libreria standard crypt. Quindi il nostro hash è $1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0: in realtà sono 3 sezioni separate da $. Sostituirò il delimitatore con uno spazio per renderlo visivamente più chiaro:

$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
 1 oaagVya9 NMvf1IyubxEYvrZTRSLgk0
  • 1 significa "algoritmo numero 1" che è un po 'complicato , ma usa MD5. Ci sono molti altri che sono molto meglio , ma questo è il nostro esempio.
  • oaagVya9 è il nostro sale. Saccheggiato proprio lì dentro con il nostro hash.
  • NMvf1IyubxEYvrZTRSLgk0 è la somma MD5 effettiva, codificata in base64.

Se eseguo nuovamente il processo, ottengo un hash completamente diverso con un sale diverso. In questo esempio, ci sono circa 1014 modi per memorizzare questa password. Tutti questi sono per la password "baseball":

$1$9XsNo9.P$kTPuyvrHqsJJuCci3zLwL.
$1$nLEOCtx6$uSnz6PF8q3YuUhB3rLTC3/
$1$/jZJXTF3$OqDuk8T/cEIGpeKWfsamf.
$1$2lC.Cb/U$KR0jkhpeb1sz.UIqvfYOR.

Ma, se specifico deliberatamente il sale che voglio controllare, restituirò il risultato atteso:

[tylerl ~]$ openssl passwd -1 -salt oaagVya9
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

E questo è il test che eseguo per verificare se la password è corretta. Trova l'hash memorizzato per l'utente, trova il sale salvato, riesegui lo stesso hash usando il sale salvato, controlla se il risultato corrisponde all'hash originale.

Implementare questo da soli

Per essere chiari, questo post non è una guida all'implementazione. Non salare semplicemente il tuo MD5 e chiamarlo buono. Questo non è abbastanza nel clima di rischio di oggi. Dovrai invece eseguire un processo iterativo che esegue la funzione hash migliaia di volte. Questo è stato spiegato altrove molte volte, quindi non esaminerò il "why" qui.

Esistono diverse opzioni consolidate e affidabili per farlo:

  • crypt: la funzione che ho usato sopra è una variante precedente del meccanismo di hashing della password unix crypt incorporato- in tutti i sistemi operativi Unix/Linux. La versione originale (basata su DES) è orribilmente insicura; non lo prendere nemmeno in considerazione. Quello che ho mostrato (basato su MD5) è migliore, ma ancora non dovrebbe essere usato oggi. Le variazioni successive, comprese le variazioni SHA-256 e SHA-512, dovrebbero essere ragionevoli. Tutte le varianti recenti implementano più round di hash.

  • bcrypt: la versione blowfish della chiamata funzionale crypt menzionata sopra. Sfrutta il fatto che blowfish ha un processo di impostazione della chiave molto costoso e accetta un parametro "cost" che aumenta di conseguenza il tempo di impostazione della chiave.

  • PBKDF2: ("Funzione di derivazione delle chiavi basata su password versione 2") Creato per produrre chiavi crittografiche efficaci da semplici password, questo è l'unica funzione elencata qui che in realtà ha un RFC . Esegue un numero configurabile di round, con ogni round ha la password e il risultato del round precedente. Il primo round usa un sale. Vale la pena notare che il suo scopo originale previsto è creare chiavi forti, non memorizzare le password, ma la sovrapposizione degli obiettivi rende questa soluzione affidabile anche qui . Se non avevi librerie disponibili e sei stato costretto a implementare qualcosa da zero, questa è l'opzione più semplice e meglio documentata. Anche se, ovviamente, è sempre meglio usare una libreria ben controllata.

  • scrypt: un sistema introdotto di recente progettato specificamente per essere difficile da implementare su hardware dedicato. Oltre a richiedere più round di una funzione di hashing, scrypt ha anche uno stato di memoria di lavoro molto grande, in modo da aumentare il requisito RAM per le implementazioni. molto nuovo e per lo più non provato, sembra almeno sicuro come gli altri, e forse il più sicuro di tutti.

402
tylerl

Tecnicamente puoi comunque usare un tavolo Rainbow per attaccare gli hash salati. Ma solo tecnicamente. Un hash salato sconfigge gli attacchi del tavolo Rainbow, non aggiungendo cripto magia, ma semplicemente aumentando esponenzialmente le dimensioni del tavolo Rainbow richiesto per trovare con successo una collisione.

E sì, dovrai conservare il sale :)

49
xkcd

Non viene aggiunto dopo l'hash. Viene aggiunto prima dell'hash, quindi l'hash è completamente diverso per ogni sale.

Non lo è

hash abcd = defg
store 123defg (for user with 123 salt) and 456defg (for user with 456 salt)  

È

hash 123abcd = ghij 
hash 456abcd = klmn
23
AJ Henderson

Per gli hash delle password, devi usare qualcosa come PBKDF2/RFC2898/PKCS5v2 , Bcrypt o Scrypt, che ti consentono di selezionare un numero di iterazioni ("fattore di lavoro"), anziché solo uno . PBKDF2, ad esempio, utilizza HMAC hash con chiave con un noto algoritmo hash (in genere SHA-512, SHA-256 o SHA-1) internamente per un numero di iterazioni, preferibilmente da decine a centinaia di migliaia, il più alto possibile senza che gli utenti si lamentino, in sostanza.

Il motivo del gran numero di iterazioni è rallentare un utente malintenzionato, che a sua volta riduce lo spazio delle chiavi che possono attraversare in un determinato periodo di tempo, quindi non possono attaccare efficacemente le password migliori. "password" e "P @ $$ w0rd" verranno decifrati indipendentemente da un attacco offline, ovviamente.

Hai ragione, ogni riga (utente) ha bisogno del proprio sale lungo generato in modo univoco, crittograficamente casuale. Quel sale è immagazzinato in forma di testo in chiaro.

Con PBKDF2, Bcrypt o Scrypt, consiglierei anche di memorizzare il numero di iterazioni (fattore di lavoro) nel database anche in testo normale, quindi è facile cambiare (personalmente, uso un numero un po 'randomizzato di iterazioni - se è sempre diverso , quindi c'è meno paura di "oh no, un piccolo cambiamento potrebbe rovinare tutto - NON CAMBIARE MAI QUESTO DI NUOVO" dalla direzione o da altri sviluppatori)

Si noti che quando si utilizza PBKDF2 per l'hash della password, non chiedere mai un output più grande dell'output hash nativo - per SHA-1, che è 20 byte, e per SHA-512, che è 64 byte.

Per fornire esempi concreti di PBKDF2 con due diversi sali:

(Risultati di outputbyte iterazioni password iterazioni PBKDF2 HMAC)

  • PBKDF2 HMAC-SHA-512 MyPass vA8u3v4qzCdb 131072 64
    • 2e3259bece6992f012966cbf5803103fdea7957ac20f3ec305d62994a3f4f088f26cc3889053fb59a4e3c282f55e9179695609ee1147cffae1455880993ef874
  • PBKDF2 HMAC-SHA-512 MyPass l6eZQVf7J65S 131072 64
    • 1018ad648096f7814bc2786972eb4091f6c36761a8262183c24b0f4d34abb48073ed2541ee273220915638b46ec14dfb2b23ad64c4aa12f97158340bdc12fc57
15

Oltre a ciò che ha detto Tylerl, è importante sottolineare che nella crittografia moderna, i sali non sono non usati per proteggere dai tavoli Rainbow. Nessuno usa davvero i tavoli Rainbow. Il vero pericolo è la parallelizzazione:

  • Se non hai sale o solo un sale statico e rubo al tuo DB un milione di hash, posso lanciare tutti i miei core a forza bruta, e ogni core attaccherà contemporaneamente un milione di hash, perché ogni volta che premo qualsiasi delle stringhe utilizzate come password, vedrò una corrispondenza hash. Quindi ho bisogno di esaurire lo spazio di ricerca na volta per decifrare una milioni password. Questa è una scala completamente realistica di perdita di password e un obiettivo abbastanza attraente da lanciare un paio di dozzine di GPU o persino un FPGA personalizzato. Anche se esaurisco solo il 30% inferiore dello spazio di ricerca, continuerò a camminare con circa 500.000 password del mondo reale. Queste password verranno quindi utilizzate per creare il mio dizionario, quindi la prossima volta che qualcuno perde un hash DB, ne creo il 90% in poche ore.
  • Se invece ogni singola password viene l'hash con il suo sale unico, allora dovrò attaccare ognuna di esse singolarmente, perché anche le password identiche avranno hash completamente diversi memorizzati. Ciò significa che forse potrei usare la mia costosa e assetata fattoria GPU/FPGA per attaccare gli obiettivi di coppia di alto valore (diciamo, se Obama fosse il tuo utente, quindi ottenere la sua password giustificherebbe comunque le spese), ma non otterrò diverse centinaia di migliaia di password gratuitamente da questo. Se volessi ottenere tutte le password milioni, dovrei fare una ricerca completa della forza bruta a milioni volte.

Ed è per questo che qualsiasi sale, statico o no, ti proteggerà dai tavoli Rainbow preparati purché non sia ampiamente usato, ma solo i sali per hash unici ti proteggeranno dal vero pericolo di usare molta potenza di calcolo parallela per rompere tutto subito.

14
mathrick

È più sicuro perché quando più persone hanno la stessa password avranno hash diversi.

Implementazione semplice con Python:

import hashlib

passwordA = '123456'
passwordB = '123456'

hashlib.md5(passwordA).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

hashlib.md5(passwordB).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

E ora aggiungiamo sale:

saltA = 'qwerty'
salbB = 'asdfgh'

passA = passwordA + saltA
passB = passwordB + saltB

hashlib.md5(passA).hexdigest()
'086e1b7e1c12ba37cd473670b3a15214'

hashlib.md5(passB).hexdigest()
'dc14768ac9876b3795cbf52c846e6847'

Questa è una versione molto semplificata. Puoi aggiungere sale dove preferisci. All'inizio/medio/fine della password.

Salt è molto utile, soprattutto quando hai molti utenti, quindi ognuno di loro avrà hash diversi. Ora immagina la probabilità di avere le stesse password per milioni di account, come Facebook o Google o Twitter.

11
zakiakhmad

Innanzitutto, se due utenti usano la password "baseball" piuttosto debole, allora decifrare una password non aiuta affatto a decifrare la seconda password a causa del salting. Senza salare, hai crackato due password al prezzo di una.

In secondo luogo, le tabelle Rainbow contengono hash precalcolati. Quindi un cracker potrebbe cercare l'hash del "baseball" in un tavolo Rainbow con voci gazillion. Molto più veloce rispetto al calcolo degli hash di gazillion nella tabella Rainbow. E questo è impedito dalla salatura.

E ora importante: alcune persone hanno buone password, altre hanno cattive password. Se hai un milione di utenti e tre usano la stessa password, devi solo sapere che la password è debole. Senza salare, hai tre hash identici. Quindi, se qualcuno ruba il tuo database di hash, può immediatamente vedere quali utenti hanno password deboli e concentrarsi sul crack di quelle. "Baseball" molto più facile da decifrare di 1keOj29fa0romn. Senza salare, spiccano le password deboli. Con la salatura, il cracker non ha idea di quali password siano deboli e quali siano difficili da decifrare.

8
gnasher729

Il fatto che l'hash sia salato fa la differenza solo se l'attaccante ha l'hash della password. Senza sale, l'hash può essere attaccato con una tabella Rainbow: un dizionario precalcolato che associa le password agli hash. Un salt N-bit aumenta il requisito di archiviazione per una tabella Rainbow e il tempo per calcolare quella tabella di un fattore di 2 ** N. Ad esempio, con un salt a 32 bit, solo una singola voce del dizionario delle tabelle Rainbow, dire per la password passw0rd, richiede molti gigabyte di spazio di archiviazione, rendendo una tabella Rainbow molto costosa utilizzando l'hardware di archiviazione corrente. Quindi, quando è presente un salt, l'attaccante viene ridotto a un attacco di forza bruta sul set specifico di hash password che sono stati ottenuti.

Però:

  • per le password deboli, un attacco di forza bruta avrà successo in un tempo relativamente breve.
  • password sufficientemente forti non saranno trovate in una tabella Rainbow.
  • se l'attaccante ha accesso agli hash, la sicurezza del sistema è già stata compromessa: i sistemi e i protocolli moderni non rivelano i loro hash delle password. Se l'attaccante non è in grado di accedere al database delle password, le password possono anche essere archiviate in testo normale.
  • se un utente malintenzionato deve compromettere il sistema per arrivare agli hash al fine di invertire le password da essi, le uniche password che hanno valore per l'attaccante sono quelle che vengono riutilizzate per altri domini di sicurezza a cui l'attaccante non ha ancora accesso. Le password che non vengono riutilizzate non hanno alcun valore (e certamente meno valore di altre informazioni sensibili associate agli account).

Dì che l'utente joewestlake usa la password god1234. L'attaccante lo inverte istantaneamente usando un tavolo Rainbow. (O entro pochi minuti dal cracking usando un attacco a forza bruta, se l'hash è salato, poiché la password è così male.) Ora il problema è che joewestlake ha usato anche god1234 per il suo account Gmail e per l'online banking, oops! Ora l'attaccante legge le e-mail di Joe e impara abbastanza su Joe in modo che possa facilmente rispondere alla domanda "come si chiamava il tuo primo animale domestico" quando accede all'online banking di Joe.

Quindi, la logica dei sali è che in qualche modo proteggono gli utenti rendendo le password di media sicurezza più difficili da invertire: le password che, senza un sale, potrebbero ragionevolmente essere dovrebbe essere trovato in un tavolo Rainbow, ma che sono abbastanza forti da costringerli individualmente a forzare il bruto impiegano molto tempo. Ma i sali forniscono questo vantaggio solo nel caso in cui gli hash siano compromessi, il che costituisce già una grave violazione della sicurezza e il vantaggio è solo per quegli utenti che riutilizzano le password di media sicurezza in altri sistemi.

Say Joe invece utilizzava una password composta da 10 caratteri e simboli alfanumerici casuali. Potrebbe essere ancora in un tavolo Rainbow, ma richiede molto lavoro. Quindi, anche se Joe ha usato la stessa password per Gmail e l'online banking, è sicuro, grazie al sale. Il cracker fa funzionare il suo crack da forza bruta per forse diverse ore, forse giorni. Il crack genera numerose password deboli da altri utenti dello stesso sistema che hanno password deboli. L'attaccante è soddisfatto di quella resa e smette di craccare; La password di Joe non viene mai annullata.

Inoltre, se viene rilevata la violazione e si consiglia agli utenti (incluso Joe) di modificare le password, Joe ha la possibilità di superare i tentativi di cracking dell'attaccante, anche se l'attaccante persiste nell'attaccare l'intero spazio della password di media sicurezza che include la password di Joe . Joe lo sa, la password che ha usato sul sistema compromesso è esattamente la stessa della sua password Gmail e bancaria, quindi si affretta a cambiare quelle altre due. Il salt aiuta qui perché fa guadagnare tempo agli utenti che riutilizzano la password per cambiare la loro password. Il sale non aiuterà quelli con password molto deboli che vengono violate in pochi minuti, ma gli utenti di password che richiedono ore o giorni per decifrare hanno una possibilità di combattere.

1
Kaz