Best practice: password salate e pepate?


145

Mi sono imbattuto in una discussione in cui ho appreso che quello che stavo facendo non era in realtà salare le password ma scrutarle, e da allora ho iniziato a fare entrambe le cose con una funzione come:

hash_function($salt.hash_function($pepper.$password)) [multiple iterations]

Ignorando l'algoritmo hash scelto (voglio che sia una discussione su sali e peperoni e non algoritmi specifici ma ne sto usando uno sicuro), è un'opzione sicura o dovrei fare qualcosa di diverso? Per coloro che non hanno familiarità con i termini:

  • Un salt è un valore generato casualmente di solito memorizzato con la stringa nel database progettato per rendere impossibile l'uso delle tabelle hash per decifrare le password. Poiché ogni password ha il suo sale, devono essere tutte forzate individualmente per decifrarle; tuttavia, poiché il salt è archiviato nel database con l'hash della password, un compromesso del database significa perdere entrambi.

  • Un pepe è un valore statico a livello di sito memorizzato separatamente dal database (di solito codificato nel codice sorgente dell'applicazione) che deve essere segreto. Viene utilizzato in modo tale che un compromesso del database non provochi la forzatura forzata dell'intera tabella delle password dell'applicazione.

C'è qualcosa che mi manca ed è la salatura e il peppering delle mie password l'opzione migliore per proteggere la sicurezza del mio utente? C'è qualche potenziale difetto di sicurezza nel farlo in questo modo?

Nota: ipotizzare ai fini della discussione che l'applicazione e il database siano archiviati su macchine separate, non condividano password ecc., Pertanto una violazione del server del database non implica automaticamente una violazione del server delle applicazioni.


3
Non abbastanza un duplicato, ma estremamente correlati: stackoverflow.com/questions/16594613/...
ircmaxell

2
Duplicazione su più siti: security.stackexchange.com/q/3272/2113
Jacco

Risposte:


306

Ok. Visto che devo scriverne ancora e ancora , farò un'ultima risposta canonica sul solo pepe.

L'apparente Upside Of Peppers

Sembra abbastanza ovvio che i peperoni dovrebbero rendere più sicure le funzioni di hash. Voglio dire, se l'attaccante ottiene solo il tuo database, le password degli utenti dovrebbero essere sicure, giusto? Sembra logico, giusto?

Ecco perché così tante persone credono che i peperoni siano una buona idea. Ha senso".

La realtà dei peperoni

Nel campo della sicurezza e della crittografia, "avere un senso" non è abbastanza. Qualcosa deve essere dimostrabile e ha senso per essere considerato sicuro. Inoltre, deve essere implementabile in modo sostenibile. Il sistema più sicuro che non può essere mantenuto è considerato insicuro (perché se una parte di quella sicurezza si rompe, l'intero sistema cade a pezzi).

E i peperoni non si adattano né ai modelli dimostrabili né a quelli mantenibili ...

Problemi teorici con i peperoni

Ora che abbiamo preparato il terreno, diamo un'occhiata a cosa c'è che non va nei peperoni.

  • Nutrire un hash in un altro può essere pericoloso.

    Nel tuo esempio, lo fai hash_function($salt . hash_function($pepper . $password)).

    Sappiamo dall'esperienza passata che "semplicemente alimentare" un risultato hash in un'altra funzione hash può ridurre la sicurezza complessiva. Il motivo è che entrambe le funzioni di hash possono diventare un bersaglio di attacco.

    Ecco perché algoritmi come PBKDF2 usano operazioni speciali per combinarli (hmac in quel caso).

    Il punto è che sebbene non sia un grosso problema, non è nemmeno una cosa banale da buttare in giro. I sistemi di crittografia sono progettati per evitare casi "dovrebbero funzionare" e si concentrano invece su casi "progettati per funzionare".

    Mentre questo può sembrare puramente teorico, in realtà non lo è. Ad esempio, Bcrypt non può accettare password arbitrarie . Quindi il passaggio bcrypt(hash(pw), salt)può effettivamente comportare un hash molto più debole che bcrypt(pw, salt)se hash()restituisce una stringa binaria.

  • Lavorare contro il design

    Il modo in cui sono stati progettati bcrypt (e altri algoritmi di hashing delle password) è lavorare con un sale. Il concetto di pepe non è mai stato introdotto. Potrebbe sembrare una banalità, ma non lo è. Il motivo è che un sale non è un segreto. È solo un valore che può essere conosciuto da un attaccante. Un pepe d'altra parte, per definizione, è un segreto crittografico.

    Gli attuali algoritmi di hashing delle password (bcrypt, pbkdf2, ecc.) Sono tutti progettati per contenere un solo valore segreto (la password). L'aggiunta di un altro segreto all'algoritmo non è stata affatto studiata.

    Ciò non significa che non sia sicuro. Significa che non sappiamo se è sicuro. E la raccomandazione generale con sicurezza e crittografia è che se non lo sappiamo, non lo è.

    Quindi fino a quando gli algoritmi non vengono progettati e controllati dai crittografi per l'uso con valori segreti (peperoni), gli algoritmi attuali non dovrebbero essere usati con essi.

  • La complessità è il nemico della sicurezza

    Che ci crediate o no, la complessità è il nemico della sicurezza . Creare un algoritmo che sembra complesso può essere sicuro o potrebbe non esserlo. Ma le probabilità sono abbastanza significative che non sia sicuro.

Problemi significativi con i peperoni

  • Non è mantenibile

    L'implementazione di peperoni preclude la possibilità di ruotare la chiave pepe. Poiché il pepe viene utilizzato all'ingresso della funzione unidirezionale, non è mai possibile modificarlo per la durata del valore. Ciò significa che dovresti inventare alcuni hacks traballanti per farlo supportare la rotazione dei tasti.

    Questo è estremamente importante in quanto è richiesto ogni volta che si memorizzano segreti crittografici. Non avere un meccanismo per ruotare le chiavi (periodicamente e dopo una violazione) è un'enorme vulnerabilità della sicurezza.

    E il tuo attuale approccio peperone richiederebbe a tutti gli utenti di avere la password completamente invalidata da una rotazione, o attendere fino al prossimo accesso per ruotare (che potrebbe non essere mai) ...

    Il che sostanzialmente rende il tuo approccio un no-go immediato.

  • Richiede il lancio della tua criptovaluta

    Poiché nessun algoritmo attuale supporta il concetto di pepe, è necessario comporre algoritmi o inventarne di nuovi per supportare un pepe. E se non riesci a capire immediatamente perché è davvero una brutta cosa:

    Chiunque, dal dilettante più all'oscuro al miglior crittografo, può creare un algoritmo che lui stesso non può rompere.

    Non rotolare MAI la tua crittografia ...

Il modo migliore

Quindi, tra tutti i problemi descritti sopra, ci sono due modi per gestire la situazione.

  • Usa gli algoritmi mentre esistono

    Se usi bcrypt o scrypt correttamente (con un costo elevato), tutte le password del dizionario tranne quelle più deboli dovrebbero essere statisticamente sicure. L'attuale record di hashing criptato al costo 5 è di 71 k hash al secondo. A quel ritmo anche una password casuale di 6 caratteri richiederebbe anni per decifrare. E considerando che il mio costo minimo raccomandato è 10, questo riduce gli hash al secondo di un fattore 32. Quindi parleremmo solo di 2200 hash al secondo. A quel ritmo, anche alcune frasi del dizionario o modifiche possono essere sicure.

    Inoltre, dovremmo verificare la presenza di quelle classi deboli di password alla porta e non consentirle di entrare. Man mano che il cracking delle password diventa più avanzato, anche i requisiti di qualità delle password. È ancora un gioco statistico, ma con una corretta tecnica di archiviazione e password complesse, tutti dovrebbero essere praticamente molto sicuri ...

  • Crittografa il hash di output prima dell'archiviazione

    Esiste nel regno della sicurezza un algoritmo progettato per gestire tutto ciò che abbiamo detto sopra. È un codice a blocchi. È buono, perché è reversibile, quindi possiamo ruotare le chiavi (yay! Manutenibilità!). È buono perché viene utilizzato come progettato. È buono perché non fornisce informazioni all'utente.

    Diamo di nuovo un'occhiata a quella linea. Diciamo che un utente malintenzionato conosce il tuo algoritmo (che è necessario per la sicurezza, altrimenti è la sicurezza attraverso l'oscurità). Con un approccio tradizionale al pepe, l'attaccante può creare una password sentinella e, poiché conosce il sale e l'output, può forzare il pepe. Ok, è una possibilità, ma è possibile. Con un codice, l'attaccante non ottiene nulla. E poiché il sale è randomizzato, una password sentinella non lo aiuterà nemmeno. Quindi il meglio che rimane è attaccare il modulo crittografato. Ciò significa che devono prima attaccare l'hash crittografato per recuperare la chiave di crittografia e quindi attaccare gli hash. Ma ci sono molte ricerche sull'attacco di cifre, quindi vogliamo fare affidamento su questo.

TL / DR

Non usare i peperoni. Ci sono una serie di problemi con loro e ci sono due modi migliori: non usare alcun segreto sul lato server (sì, va bene) e crittografare l'hash di output usando un codice a blocchi prima della memorizzazione.


6
Grazie per aver incluso l'ultima parte della crittografia del valore hash, questa è una risposta con cui posso essere pienamente d'accordo. Se la crittografia diventasse parte della tua password api , non ci sarebbe motivo di non usarla, quindi forse ... (mi piacerebbe scriverne la documentazione)
martinstoeckli,

2
@martinstoeckli: Non accetterei di aggiungere il passaggio di crittografia all'API di hashing semplificata. Il motivo è che la conservazione dei segreti (chiavi) è molto più difficile di quanto si pensi, ed è abbastanza facile spararsi ai piedi. Per il 99,9% degli utenti là fuori, crypt bcrypt è più che sufficiente per tutti tranne che per le password più semplici ...
ircmaxell,

7
@ircmaxell - Dall'altro lato, non perderesti nulla. Nel peggiore dei casi, quando la chiave viene conosciuta, un utente malintenzionato deve comunque rompere l'hash BCrypt (stessa situazione senza crittografia). Ciò non equivale alla memorizzazione di una chiave per la crittografia dei dati, si tratta dell'aggiunta di un segreto sul lato server. Anche una chiave codificata proteggerebbe quelle password deboli, a condizione che l'attaccante non abbia alcun controllo sul server / codice. Questa situazione non è rara: a parte l'iniezione SQL, anche i backup eliminati, i server scartati ... possono portare a questa situazione. Molti utenti di PHP lavorano su server ospitati.
martinstoeckli,

2
@martinstoeckli Dovrei essere d'accordo con ircmaxwell qui, non credo che la crittografia appartenga alla password dell'API. Tuttavia, si potrebbe notare che per la massima sicurezza la crittografia degli hash è una disposizione aggiuntiva che può essere utilizzata.
febbraio

1
Mi è stato indicato OWASP Application Security Verification Standard 4.0 sezione 2.4.5 che consiglia di utilizzare il sale segreto (noto anche come pepper): “Verificare che venga eseguita un'iterazione aggiuntiva di una funzione di derivazione chiave, usando un valore salt che è segreto e noto solo a il verificatore. "
Michael Freidgeim,

24

Per prima cosa dovremmo parlare dell'esatto vantaggio di un peperone :

  • Il pepe può proteggere le password deboli da un attacco del dizionario, nel caso speciale, in cui l'attaccante ha accesso in lettura al database (contenente gli hash) ma non ha accesso al codice sorgente con il pepe.

Uno scenario tipico sarebbe l'iniezione di SQL, i backup eliminati, i server scartati ... Queste situazioni non sono così insolite come sembrano e spesso non sono sotto il tuo controllo (server-hosting). Se usi ...

  • Un sale unico per password
  • Un algoritmo di hashing lento come BCrypt

... le password complesse sono ben protette. È quasi impossibile forzare una password complessa in tali condizioni, anche quando si conosce il sale. Il problema sono le password deboli, che fanno parte di un dizionario della forza bruta o ne derivano. Un attacco da dizionario rivelerà quelli molto velocemente, perché testerai solo le password più comuni.

La seconda domanda è come applicare il pepe ?

Un modo spesso consigliato per applicare un pepe è quello di combinare la password e il pepe prima di passarlo alla funzione hash:

$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);

C'è un altro modo ancora migliore però:

$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);

Ciò non solo consente di aggiungere un lato server segreto, ma consente anche di scambiare $ serverSideKey, qualora ciò fosse necessario. Questo metodo comporta un po 'più di lavoro, ma se il codice esiste una volta (libreria) non c'è motivo di non usarlo.


Quindi diresti che un pepe aggiunge sicurezza a un solo sale, in breve? Grazie per l'aiuto su come implementare.
Glitch Desire,

1
@LightningDust - Sì, per password deboli, purché il pepe rimanga segreto. Riduce alcuni tipi ben definiti di minacce.
martinstoeckli,

@martinstoeckli è sicuramente un buon modo per implementarlo. È bello vedere che qualcuno con qualche esperienza di sicurezza supporta questo metodo. Una AES_ENCRYPT($passwordHash, $serverSideKey)chiamata MySQL sarebbe anche un modo appropriato di implementarlo?
febbraio

1
@Foo_Chow - Non conosco l'implementazione della funzione MySQL, ma sembra che abbiano usato la modalità EBC, per evitare il vettore IV. Insieme al testo in chiaro noto (i valori hash iniziano sempre con gli stessi caratteri), questo potrebbe essere un problema. Sulla mia homepage ho pubblicato un'implementazione di esempio, che gestisce questa crittografia.
martinstoeckli,

@martinstoeckli interessante, non troppo familiare con i concetti; tuttavia sembra che un IV sarebbe desiderabile per i risultati più robusti. Non sembra aggiungere molto sovraccarico per il vantaggio aggiunto.
febbraio

2

Il punto di sale e pepe è quello di aumentare il costo di una ricerca password pre-calcolata, chiamata tabella arcobaleno.

In generale, cercare di trovare una collisione per un singolo hash è difficile (supponendo che l'hash sia sicuro). Tuttavia, con hash brevi, è possibile utilizzare il computer per generare tutti gli hash possibili in una ricerca su un disco rigido. Questo si chiama Tavolo Arcobaleno. Se crei una tabella arcobaleno, puoi uscire nel mondo e trovare rapidamente password plausibili per qualsiasi hash (non salato non bollato).

Il punto di pepe è rendere unica la tabella arcobaleno necessaria per hackerare l'elenco di password. Quindi sprecare più tempo sull'attaccante per costruire il tavolo arcobaleno.

Il punto del sale è tuttavia rendere la tabella arcobaleno per ogni utente unica per l'utente, aumentando ulteriormente la complessità dell'attacco.

In realtà il punto della sicurezza informatica non è quasi mai renderlo (matematicamente) impossibile, solo matematicamente e fisicamente impraticabile (ad esempio nei sistemi sicuri ci vorrebbe tutta l'entropia nell'universo (e altro) per calcolare la password di un singolo utente).


Quindi un sale + pepe offre più sicurezza di un semplice sale? O sarebbe meglio lasciar cadere il pepe e fare più iterazioni di Scrypt?
Glitch Desire,

2
La cosa principale di una tabella arcobaleno è che non ne crei una per un attacco specifico, ne scarichi una preesistente. Ci sono lunghe tabelle arcobaleno disponibili per i più diffusi algoritmi di hash solo a google!
Richard,

1
@LightningDust Non riesco a pensare a nessun motivo me stesso. Tuttavia Richard nell'altro thread ne ha inventato uno. Puoi nascondere il pepe nel tuo codice sorgente, il che significa un altro posto a cui il tuo attaccante deve accedere, solo per ottenere un tavolo arcobaleno insieme.
Aron,

@Aron - Beh, questo è quello che ho pensato, dal momento che abbiamo server delle applicazioni separati dai server di database (vale a dire, se arrivi rootsul nostro server db, non hai ancora accesso al nostro server delle applicazioni), che nascondiamo pepe nel codice sorgente (in il nostro file di configurazione) fornirebbe ulteriore sicurezza.
Glitch Desire,

1

Non riesco a vedere la memorizzazione di un valore codificato nel codice sorgente come rilevante per la sicurezza. È sicurezza attraverso l'oscurità.

Se un hacker acquisisce il tuo database, sarà in grado di iniziare a forzare forzatamente le password degli utenti. Non ci vorrà molto perché quell'hacker identifichi il tuo pepe se riesce a decifrare alcune password.


1
Renderebbe inutile una tabella arcobaleno precalcolata per una tabella di password non salata. In breve, anche se l'attaccante conosceva il tuo pepe avrebbe bisogno di creare un nuovo tavolo arcobaleno.
Aron,

3
Rafforza l'hash basato su dati non disponibili nel database, il che è positivo. Le cose nel database possono essere potenzialmente rivelate nelle vulnerabilità - è meno probabile che un valore nel codice sia accessibile allo stesso modo.
Richard,

I sali sono funzioni a senso unico, anche se forzare con successo una password ti darebbe solo quella password e non ti aiuterebbe a ottenere il valore del pepe stesso.
Glitch Desire,

1
@LightningDust Penso che intendi "Gli hash sono funzioni botola". Sì, è impossibile capire il tuo sale e / o pepe da un hash sicuro (in effetti questa è la definizione di un hash sicuro).
Aron,

6
@Aron Security Through Obscurity può essere una tecnica valida utilizzata come strato di difesa. Il punto è che non dovrebbe mai essere invocato come difesa, ma invece usato per "rallentare un attaccante". Se così non fosse, qualcosa come un honeypot non verrebbe utilizzato. Invece, possiamo effettivamente utilizzare la sicurezza attraverso l'oscurità per aiutare a rallentare gli aggressori, purché non ci affidiamo a esso per la sicurezza della nostra applicazione.
Ircmaxell,
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.