E 'sicuro / saggio memorizzare un sale nello stesso campo della password con hash?

60

Utilizzando Argon2 per le password di hashing 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 prima di p= sono parametri, il corpo di p= è il sale e l'ultima parte è la password con hash.

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

    
posta TheHonestAtheist 06.04.2018 - 16:26
fonte

7 risposte

116

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

So che questo potrebbe sembrare un po 'non intuitivo per le persone provenienti da uno sfondo di database, in cui il modus operandi è quello di normalizzare i dati e l'utilizzo di stringhe serializzate è considerato un brutto attacco. Ma da una pratica di sicurezza, questo ha perfettamente senso.

Perché? Poiché 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 non deve preoccuparsi di cosa significhi realmente quelle parti fastidiose.

Questa è una buona cosa, perché la maggior parte degli sviluppatori sono esseri umani imperfetti (lo so, perché ne sono uno anch'io). Se lasci che raccolgano quella stringa e poi provi a montarla di nuovo insieme, probabilmente creeranno problemi, come dare a tutti gli utenti lo stesso sale o niente sale.

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

    
risposta data 06.04.2018 - 16:36
fonte
47

Quello che ti manca è che gli hash funzionano sui dati originali, meno la stringa originale. Quando si desidera convalidare una stringa con un hash, si prende la stringa fornita, oltre ai dati hash originali (costo, sale, 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 decodificata , è rehashed ).

Avere il sale non aiuta la forza bruta. Il sale è una parte essenziale di un hash nello stesso modo in cui i tumbler fanno parte di una serratura. Se lo fai fuori, nessuno può usarlo.

La separazione della memoria è inutile. Dovrai riassemblare l'hash completato per convalidarlo nella maggior parte dei casi. Ecco perché tutti i componenti sono memorizzati in una sola stringa pratica per impostazione predefinita.

    
risposta data 06.04.2018 - 19:34
fonte
8

Sì, puoi archiviarlo in un unico 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 usando il formato:

"$id$salt$hashed", the printable form of a password hash as produced by crypt (C), where "$id" is the algorithm used. (On GNU/Linux, "$1$" stands for MD5, "$2a$" is Blowfish, "$2y$" is Blowfish (correct handling of 8-bit chars), "$5$" is SHA-256 and "$6$" is SHA-512,[4] other Unix may have different values, like NetBSD.

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

Il sale non vuole essere segreto (o almeno non più segreto dell'hash). Il suo scopo principale è quello di rendere gli attacchi forzanti brute 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 dei sali ma anche dei parametri. Cose come l'algoritmo di hashing, il conteggio delle iterazioni e il sale. In ogni caso, non memorizzarlo nel codice, appartengono ancora al DB.

Immagina di avere un sacco di utenti e hai usato SHA1 come algoritmo di hashing. Quindi il campo del tuo database dovrebbe essere qualcosa come SHA1: SALT: HASH .

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

Normalmente dovresti distribuire del codice in modo che quando un utente si connette, verifica la password e, se valida, re-hash la password con un nuovo algoritmo. Ora il campo per l'utente è simile a questo: BCRYPT: SALT: HASH .

Tuttavia, alcuni utenti potrebbero trovarsi su SHA1 e altri su BCRYPT, e poiché questo è a livello di utente, sono necessari i parametri che indicano al tuo codice quali utenti devono trovarsi nel Database.

In breve, memorizzare i parametri e l'hash in un singolo campo è OK, ma dividerli per qualsiasi motivo (efficienza, codice più semplice ecc.) è anche OK. Cosa non va bene è la memorizzazione nel codice:)

TL: DR

Troy Hunt ha recentemente pubblicato un podcast che suggerisce che invece di migrare a BCRYPT nel modo sopra descritto, è più efficace prendere semplicemente tutti gli hash SHA1 attualmente nel DB e cancellarli con BCRYPT.

Effettivamente BCRYPT(SHA1(clear_password))

Quando un utente si connette avresti

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

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

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

    
risposta data 06.04.2018 - 19:00
fonte
4

Da un punto di vista della sicurezza, non importa se la password salt e hash è memorizzata in un singolo campo o in campi separati, anche se mi piacerei indirizzare verso un singolo campo per semplicità. L'unico motivo per separarli è se il codice dell'applicazione deve passare separatamente in Salt e nella password alla funzione di convalida. Se il tuo codice applicazione richiede solo una singola stringa combinata, potresti anche memorizzarla in questo modo.

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

    
risposta data 06.04.2018 - 21:27
fonte
3

Is it acceptable to store this in one field in a SQL database (varchar(99) in this case)

No. La dimensione dei dati potrebbe cambiare in qualche momento. Dovrebbe essere usato un campo varchar (MAX) a meno che le specifiche dichiarino che la dimensione sarà sempre esattamente 99 e non ci sarà alcuna variazione da quel mai . Lascia che il database si occupi dei requisiti di archiviazione.

    
risposta data 07.04.2018 - 21:36
fonte
1

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

Un sale serve a pochi scopi (che io possa pensare)

  1. Impedisci agli attacchi di dizionario

Un attacco di dizionario è dove una parola logica viene usata come parte di una password. L'archetipo è la parola password o anche P@ssW0rd . Le persone sono imperfette e per loro è più facile ricordare le parole, quindi stringhe casuali di lettere e numeri. Un attacco di dizionario si basa su questo per abbreviare il percorso di un attacco di forza bruta. Ovviamente se aggiungiamo un pezzo di roba a caso, allora rende questo tipo di attacco impossibile, o inutile e li rimette a bruto forzando il tutto.

Se un utente malintenzionato conosce il sale utilizzato, dovrebbe modificare tutti i file del dizionario per ogni password e ciò presuppone che sappiano come viene aggiunto il sale alla password originale. Un grande vantaggio di un elenco di dizionari è che dici di prendere 1000 password e 1 milione di parole del dizionario. Poi li passi in rassegna cercando di ottenere alcune partite con password più deboli. Quindi, modificare 1 milione di parole 1000 volte non è proprio pratico.

  1. Prevenire attacchi da tavolo Hash o Rainbow.

Una tabella Rainbow è dove gli hash sono pre-calcolati e memorizzati in una sorta di database. Ad esempio, puoi prendere MD5 e iniziare a fare hashing a caso e salvarlo. Poi, quando vuoi craccare una password, devi solo cercare nella tabella arcobaleno.

Se un attaccante ha il sale, è necessario ricompilare la tabella arcobaleno per ogni sale utilizzato. Il vantaggio di questo attacco sta avendo quei dati compilati in anticipo e riutilizzandoli più e più volte. Questo li rimette in bruta-forzando la password. Salendo e salando tutte le password in modo diverso, in pratica significa che è necessario ricalcolare la tabella arcobaleno per ogni sale. Questo è il motivo per cui è importante utilizzare diversi sali rispetto a ciascuna password.

Summery

Nessuno di questi motivi si basa 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 andare a pubblicizzarlo, ma c'è un modo di dire sulla sicurezza basato 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 ti aiuti.

    
risposta data 08.04.2018 - 02:42
fonte
0

Il sale è appena usato per bloccare gli attacchi dei tavoli arcobaleno. Quindi il tuo sale potrebbe essere memorizzato con la password hash come è fatto sul più recente sistema GNU / Linux dove il sale è memorizzato in / etc / shadow.

    
risposta data 06.04.2018 - 16:36
fonte

Leggi altre domande sui tag