Domanda:
È sicuro / saggio memorizzare un sale nello stesso campo della password con hash?
PenumbraBrah
2018-04-06 19:26:27 UTC
view on stackexchange narkive permalink

Utilizzando Argon2 per l'hashing delle password nella mia applicazione, ho notato che genera una stringa come questa (ad esempio per la password "rabbit"):

  $ argon2i $ v = 19 $ m = 65536, t = 3, p = 1 $ YOtX2 // 7NoD / owm8RZ8llw == $ fPn4sPgkFAuBJo3M3UzcGss3dJysxLJdPdvojRF20ZE =  

La mia comprensione è che tutto ciò che è precedente a p = parametri, il corpo del p = è il sale e l'ultima parte è la password con hash.

È accettabile memorizzarlo in un campo in un database SQL ( varchar (99) in questo caso), o la stringa dovrebbe essere separata nelle sue parti costitutive? Devo memorizzare il sale separatamente dalla password con hash e mantenere i parametri in codice?

[molto fortemente correlato] (https://security.stackexchange.com/questions/17421/how-to-store-salt)
Se utilizzi un [_pepper_] (https://security.stackexchange.com/questions/3272/password-hashing-add-salt-pepper-or-is-salt-enough), puoi memorizzarlo fuori dal database.
La funzione PHP [password_hash] (http://php.net/manual/en/function.password-hash.php) memorizza anche il salt con la stringa con hash (ad esempio: `$ 2y $ 10 $ .vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk`)
"varchar (99)" sembra terribilmente stretto.E se la prossima versione della libreria hash aggiunge parametri o allunga l'hash?Il tuo database non ha "varchar (MAX)" o simili?
Sette risposte:
Anders
2018-04-06 19:36:50 UTC
view on stackexchange narkive permalink

Dovresti memorizzarlo in un unico campo. Non cercare di dividerlo in parti.

So che questo potrebbe sembrare un po 'poco intuitivo per le persone che provengono dallo sfondo di un database, dove il modus operandi è normalizzare i dati e l'uso di stringhe serializzate è considerato un brutto trucco. Ma da una pratica di sicurezza, questo ha perfettamente senso.

Perché? Perché l'unità più piccola su cui il singolo sviluppatore deve operare è quella stringa completa. Questo è ciò che l'app deve passare alla libreria hash per verificare se una password fornita è corretta o meno. Dal punto di vista degli sviluppatori, la libreria hash può essere una scatola nera e lei non deve preoccuparsi di cosa significano effettivamente quelle parti fastidiose.

Questa è una buona cosa, perché la maggior parte degli sviluppatori sono esseri umani imperfetti (lo so , perché lo sono anch'io). Se lasci che raccolgano quella corda e poi provi a rimetterla insieme, probabilmente rovineranno le cose, come dare a tutti gli utenti lo stesso sale o niente sale.

Anche memorizzare solo i parametri nel codice è una cattiva idea. Man mano che i processori diventano più veloci, potresti voler aumentare il fattore costo in futuro. Durante la fase di migrazione, password diverse avranno fattori di costo diversi. Quindi avrai bisogno di informazioni a livello di password su quale fattore di costo è stato utilizzato per l'hashing.

Molte librerie crittografiche prendono il segreto e il sale come parametri separati.Solo da questo punto di vista, sembra prudente conservare il digest e il sale / entropia in campi separati.Se li conservi separatamente, non devi nemmeno usare una lunghezza uniforme per il sale.Puoi modificare la versione dei tuoi algoritmi e supportarne più di uno alla volta, consentendoti di spingere facilmente gli utenti a un algoritmo più nuovo e più potente senza nemmeno richiedere una modifica della password e così via.
@Craig Molte vecchie librerie lo fanno, ma direi che oggigiorno è considerato un cattivo design.Per quanto riguarda gli algoritmi di controllo delle versioni, puoi farlo anche con l'intera stringa in una colonna.
Questo è il motivo per cui adoro lo scambio di stack.Ogni giorno imparo qualcosa che non sapevo di non sapere.
Non è solo dal punto di vista delle pratiche di sicurezza che ha senso.Ha ancora senso dal punto di vista della normalizzazione date le ragioni che esponi.
Questo ha anche il vantaggio di essere a prova di futuro;se decidi di modificare i parametri di hashing in un secondo momento, i vecchi hash nel database continueranno a funzionare _ (fintanto che usi le funzioni di libreria per confrontare gli hash, come dovresti fare con Argon2, piuttosto che confrontare direttamente le stringhe di hash) _
@Anders A quale libreria stai pensando che supporti il controllo delle versioni della password memorizzata con un unico campo password?Posso vedere come farlo funzionare e l'approccio ha abbastanza fascino, ma non ne ho mai visto uno in natura.
@Voo Qualsiasi libreria.Tutte le informazioni di cui hai bisogno - algoritmo, parametri, sale - sono nella stringa che memorizzi in una singola colonna.
@Anders Non è più una scatola nera se devo definire il mio formato per come memorizzare le parti separate in una singola stringa e devo convertire tra la tupla (algoritmo, hash, salt) e la stringa da solo.Semmai ciò rende molto più probabile che in qualche modo introduca errori.Pensavo che l'idea fosse quella di evitare che lo sviluppatore avesse a che fare con le parti separate?
@Voo Sì, il punto è non modificare la stringa.Non farlo mai.Non volevo suggerirlo.Penso che ci stiamo fraintendendo a vicenda.
@Voo spring-security versione 5 sta andando in questa direzione: https://docs.spring.io/spring-security/site/docs/current/reference/html/core-services.html#pe-dpe.L'unica funzionalità che trovo mancante è che la libreria non dà l'opportunità all'applicazione di migrare il campo della password con hash allo schema di codifica predefinito (se non lo si utilizza)
Per coloro che cercano un esempio di una libreria che memorizzi in modo trasparente tutti i parametri, incluso l'algoritmo, in una stringa e consenta di eseguire facilmente l'aggiornamento a impostazioni più forti, controlla [PHP's password_ * functions] (http://php.net/password), inclusi gli esempi di [password_needs_rehash] (http://php.net/manual/en/function.password-needs-rehash.php).
@Voo Questo controllo delle versioni deve essere attivato dallo sviluppatore, ma la decodifica e la ricodifica sono completamente gestite dalla libreria.
@Anders Ero interessato a quali librerie hanno effettivamente un'API che funziona con una singola stringa invece della solita tripla.Dopotutto, in questo caso è necessaria una configurazione aggiuntiva.L'API di primavera è piuttosto interessante da esaminare.
@Voo Un'altra implementazione della crittografia della password che memorizza tutte e tre le parti come una singola stringa è [bcrypt] (https://en.wikipedia.org/wiki/Bcrypt) con implementazioni per numerose lingue.
Machavity
2018-04-06 22:34:26 UTC
view on stackexchange narkive permalink

Quello che ti manca è che gli hash funzionano sui dati originali, meno la stringa originale. Quando si desidera convalidare una stringa rispetto a un hash, si prende la stringa fornita, più i dati hash originali (costo, salt, ecc.) E si genera un nuovo hash. Se il nuovo hash corrisponde a quello vecchio, la stringa viene quindi convalidata (in altre parole, la stringa non viene mai decrittografata , viene modificata ).

Avere il sale non aiuta la forza bruta. Il sale è una parte essenziale di un hashish allo stesso modo in cui i bicchieri fanno parte di una serratura. Se elimini uno dei due, nessuno può usarlo.

Separare lo spazio di archiviazione è inutile. Nella maggior parte dei casi dovrai riassemblare l'hash completato per convalidarlo. Ecco perché tutti i componenti sono memorizzati in una comoda stringa per impostazione predefinita.

L'hai spiegato in modo molto più elegante di me, in meno parole.+1
Sì, separare è inutile: non puoi usarne uno senza l'altro, non aggiorni mai l'uno senza l'altro e hanno requisiti di sicurezza identici, quindi tratta salt + password come un'unica unità indivisibile per l'archiviazione.
keithRozario
2018-04-06 22:00:48 UTC
view on stackexchange narkive permalink

Sì, puoi memorizzarlo in un singolo campo e molti database / applicazioni memorizzano l'hash salt + in un singolo campo / file ecc.

Il più famoso è Linux (che non è un DB), che memorizza l'hash nel file / etc / shadow utilizzando il formato:

"$ id $ salt $ hashed", il formato stampabile di un hash della password prodotto da crypt (C) , dove "$ id" è l'algoritmo utilizzato. (Su GNU / Linux, "$ 1 $" sta per MD5, "$ 2a $" è Blowfish, "$ 2y $" è Blowfish (corretta gestione dei caratteri a 8 bit), "$ 5 $" è SHA-256 e "$ 6 $ "è SHA-512, [4] altri Unix possono avere valori diversi, come NetBSD.

(fonte: https://en.wikipedia.org/wiki/Passwd)

Il sale non deve essere segreto (o almeno non più segreto dell'hash). Il suo scopo principale è rendere gli attacchi di forza bruta molto più difficili poiché l'attaccante deve usare un sale diverso per ogni singolo utente.

Ma la tua domanda è più sfumata, perché non stai solo chiedendo sali ma anche parametri. Cose come l'algoritmo di hashing, il conteggio delle iterazioni e il sale. In qualsiasi caso, non memorizzarlo nel codice, appartengono ancora al DB.

Immagina di avere un gruppo di utenti e di aver utilizzato SHA1 come algoritmo di hashing. Quindi il campo del tuo database lo farebbe essere qualcosa come SHA1:SALT:HASH”.

Se volessi aggiornare il tuo database a BCRYPT, come faresti?

Typi normalmente distribuiresti un po 'di codice in modo che quando un utente accede, verifichi la password e, se valida, riesci ad eseguire nuovamente l'hash della password con un algoritmo più recente. Ora il campo per l'utente ha questo aspetto: BCRYPT:SALT:HASH”.

Ma allora alcuni utenti sarebbero su SHA1 e altri su BCRYPT, e poiché questo è a livello utente, hai bisogno dei parametri che dicono al tuo codice quali sono gli utenti che devono essere nel database.

In breve, memorizzare i parametri e l'hash in un singolo campo va bene, ma suddividerli per qualsiasi motivo (efficienza, codice più semplice, ecc.) Va bene anche. Ciò che non va bene è memorizzare questo nel codice :)

Troy Hunt ha recentemente pubblicato un podcast in cui suggerisce che invece di migrare a BCRYPT nel modo sopra, è più efficace prendere semplicemente tutti gli hash SHA1 attualmente presenti il DB e l'hashing utilizzando BCRYPT.

Efficacemente BCRYPT(SHA1(clear_password))

Quando un utente accede a voi

  BCRYPT (SHA1 (clear_password)) == <db_field>  

In questo modo, tutti sulla piattaforma vengono aggiornati contemporaneamente e non hai un database con più hash formati per le password. Molto pulito e molto carino.

Penso che questa idea abbia perfettamente senso, ma anche se tutti migrano contemporaneamente, non è istantanea. A meno che tu non sia disposto ad accettare un po 'di inattività sull'app (mentre esegui nuovamente l'hash di tutte le password), ci sarà ancora un piccolo intervallo di tempo in cui alcuni utenti sono su BCRYPT e altri su SHA1, quindi il tuo DB dovrebbe ancora memorizzare parametri dell'algoritmo di hashing e il tuo codice verrebbe eseguito in base ad esso.

Conosci la cosa [Perché non dovremmo lanciare il nostro?] (Https://security.stackexchange.com/q/18197/114527)?È stato * dimostrato * che `BCRYPT (SHA1 ())` non ha questo problema?(Non hai fornito un collegamento in modo che potessi facilmente indagare e "ha perfettamente senso" non è la stessa cosa di "è vero").
Beh, ho avvertito che la frase con "penso" abbia perfettamente senso :).La mia comprensione è che se BCRYPT funziona rendendo la forza bruta più costosa, indipendentemente da quale sia l'input, che si tratti di un SHA1 o del testo in chiaro, sarà comunque più costoso per l'attaccante la forza bruta.Il BCRYPT (SHA1 ()) ha senso dal punto di vista della migrazione.
Inoltre ho trovato questo argomento qui, che ti suggerisce alcuni altri casi d'uso per SHA-ing una password prima di BCRYPT-ing.Il consenso generale del thread era che è una cosa OK da fare, ma forse dovremmo iniziare una domanda separata se non sei ancora d'accordo https://security.stackexchange.com/questions/61595/is-it-good-practice-to-sha512-passwords-before-pass-them-to-bcrypt
@keithRozario "È intuitivamente ovvio che BCRYPT (SHA1 (x)) è sicuro almeno quanto BCRYPT (x)" non è la stessa cosa di "c'è una prova di sicurezza che ...".Prima regola della crittografia: non fidarti mai del tuo intuito a meno che il tuo nome non sia djb o simile.
@MartinBonner è corretto.* È * intuitivo ma è anche sbagliato.Supponiamo che SHA1 sia rotto.Simula questo facendo restituire 1 per tutti gli input.BYCRYPT (SHA1 (x)) è chiaramente meno sicuro di BCRYPT (x) in questo scenario, allo stesso modo si consideri SHA1 (BCRYPT (x)).A seconda di * come * SHA1 viene interrotto, il concatenamento degli hash * potrebbe * rimanere valido.Ma non sarà mai più sicuro che usare solo il più sicuro dei due.Poiché idealmente influenzano gli stessi parametri nell'equazione della sicurezza.* Se * avessero un concatenamento di interazioni minimo potrebbe essere utile, ma è un bel po 'di matematica.Quindi * provato * @ AndrewMorton
@AndrewMorton Buona discussione, ma non sono convinto.Il tuo esempio di simulazione di SHA1 non funzionante facendogli restituire 1 per tutti gli input non è corretto, è come dire che se l'utente sceglie 1 come password, BCRYPT è rotto.Ma sto iniziando un altro thread perché penso che questo sia interessante.
il nuovo thread è qui: https://security.stackexchange.com/questions/183358/how-secure-is-bcryptsha1password
@keithRozario È stato Black a scriverlo.
TTT
2018-04-07 00:27:25 UTC
view on stackexchange narkive permalink

Dal punto di vista della sicurezza, non importa se il salt e la password con hash sono memorizzati in un singolo campo o in campi separati, anche se per semplicità preferirei un unico campo. L'unico motivo per separarli è se il codice dell'applicazione deve passare separatamente il salt e la password alla funzione di convalida. Se il codice dell'applicazione richiede solo una singola stringa combinata, puoi anche memorizzarlo in questo modo.

Ad esempio, l'appartenenza ad ASP.NET precedente divide l'hash della password e il sale in due campi DB e il La più recente identità ASP.NET ha l'hash e il sale in un unico campo DB e, a loro volta, le nuove funzioni sono state modificate per gestire la singola stringa come input e output.

Andrew Morton
2018-04-08 00:36:49 UTC
view on stackexchange narkive permalink

È accettabile memorizzarlo in un campo in un database SQL (varchar (99) in questo caso)

No. La dimensione dei dati potrebbe cambiare in qualche momento. Deve essere utilizzato un campo varchar (MAX) a meno che le specifiche non stabiliscano che la dimensione sarà sempre esattamente 99 e non ci saranno variazioni mai . Lascia che il database si occupi dei requisiti di archiviazione.

ArtisticPhoenix
2018-04-08 05:42:05 UTC
view on stackexchange narkive permalink

Per sapere se è più o meno sicuro, dobbiamo capire lo scopo di un sale.

Un sale ha pochi scopi (a cui posso pensare)

  1. Prevenire gli attacchi del dizionario

Un attacco del dizionario è quando una parola logica viene utilizzata come parte di una password. L'archetipo è la parola password o anche P @ ssW0rd . Le persone sono imperfette ed è più facile per loro ricordare le parole quindi stringhe casuali di lettere e numeri. Un attacco del dizionario si basa su questo per abbreviare il percorso intrapreso da un attacco di forza bruta. Ovviamente se aggiungiamo un pezzo casuale di cose ad esso, allora rende questo tipo di attacco impossibile o inutile e li rimette a forzare il tutto.

Se un utente malintenzionato conosce il salt utilizzato, dovrebbe modificare tutti i file del dizionario per ciascuna password, e questo presuppone che sappia come il salt viene aggiunto alla password originale. Un grande vantaggio di un elenco di dizionari è che tu prenda 1000 password e 1 milione di parole del dizionario. Quindi le scorri cercando di ottenere alcune corrispondenze su password più deboli. Quindi, dover modificare 1 milione di parole 1000 volte non è molto pratico.

  1. Prevenire attacchi Hash o Rainbow table.

A La tabella arcobaleno è dove gli hash vengono pre-calcolati e archiviati in una sorta di database. Ad esempio, potresti prendere MD5 e iniziare a fare l'hashing di cose casuali e salvarle. Quindi, quando vuoi decifrare una password, devi solo cercare nella tabella arcobaleno.

Se un attaccante ha il sale, deve ricompilare la tabella arcobaleno per ogni sale utilizzato. Il vantaggio di questo attacco è che i dati vengono compilati in anticipo e riutilizzati più e più volte. Questo li riporta alla forzatura bruta della password. Salando e salando tutte le password in modo diverso, ciò significa sostanzialmente che devi ricalcolare la tabella arcobaleno per ogni sale. Questo è il motivo per cui è importante utilizzare sali diversi per ciascuna password.

Estivo

Nessuna di queste ragioni fa affidamento sul fatto che il sale sia segreto. Ovviamente sono tutti meno forti se un attaccante conosce il sale. Ma le informazioni aggiuntive che ottengono li aiuteranno sempre. Quindi non direi di pubblicizzarlo, ma c'è un detto sulla sicurezza basata sull'oscurità ....

Disclaimer Non sono affatto un esperto di crittografia, ma questi sono alcuni dei principali motivi che mi vengono in mente quando penso ai sali.

Spero che questo aiuti.

Ti sbagli sul motivo tre.Il salt è pubblico, quindi l'attaccante può ancora utilizzare tutte le password di 1 carattere, tutte le password di 2 caratteri, ecc.
@MartinBonner - bene l'ho rimosso ...
maggick
2018-04-06 19:36:48 UTC
view on stackexchange narkive permalink

Il sale viene utilizzato solo per bloccare gli attacchi alle tabelle arcobaleno, quindi il tuo sale potrebbe essere memorizzato con la password con hash come avviene sul sistema GNU / Linux più recente in cui il sale è memorizzato in / etc / shadow.

Non sono sicuro di come la tua risposta si applicherebbe alle diverse colonne del database?


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...