it-swarm.dev

I sali devono essere casuali o semplicemente unici e sconosciuti?

Prima di tutto, il mio motivo è di evitare di archiviare il sale nel database come testo normale. Per quanto riguarda questa domanda, il sale non è memorizzato nel database.

Dopo la discussione nei commenti e in chat , ho escogitato una teoria:

Sembra che usando doman_name + user ID accanto a pepe fornirà una combinazione sufficiente di casualità e unicità.

Un metodo come questo fornirebbe la stessa sicurezza di un salt casuale senza dover archiviare un salt designato nel database come testo normale?

24
user26547

L'unico requisito di un sale è essere globalmente unico. Non deve avere per essere casuale e sicuramente non deve essere sconosciuto.

Nota la parola chiave a livello globale . Un salt deve essere unico non solo nel contesto del tuo database, ma nel contesto di ogni singolo database là fuori. È molto improbabile che un'e-mail o un ID utente incrementale soddisfino questo requisito. Usando un sale generato casualmente lo fa.

[~ ~ #] modifica [~ ~ #]

Ho intenzione di affrontare il tutto usando un domain + userid Come idea salata che è emersa nei commenti. Non penso che questo schema sia una buona idea soprattutto se paragonato all'uso di un sale casuale.

Se il tuo sito ha un target elevato, un utente malintenzionato potrebbe trovare utile generare una tabella Rainbow mirata all'account amministratore prima che si verifichi l'attacco. Ciò potrebbe consentirgli di accedere prima che venga scoperto l'attacco. Lo schema domain + userid Non funziona bene se si considera questa situazione perché l'account admin è generalmente compreso tra i primi userids nel sistema, specialmente quando userid viene incrementato usando un contatore.

Detto questo, l'intera discussione è davvero discutibile in pratica. La generazione di sali casuali è facile e veloce. Molte librerie di hashing delle password, in particolare quelle bcrypt lo fanno già per te. Non ha davvero senso implementare il proprio schema anche se è altrettanto sicuro. Ammettiamolo, siamo tutti pigri no? : P Perché reinventare la ruota?

27
user10211

La caratteristica importante di una password salt ( come nota correttamente Terry Chia ) è che dovrebbe essere unica a livello globale: non ci sono mai due hash password (anche su siti diversi) per avere la stessa salt.

L'uso di sali unici protegge da vari metodi di attacco correlati che potrebbero essere impiegati da un utente malintenzionato che ha compromesso il database degli utenti e desidera recuperare le password dai loro hash:

  • Prima di tutto, impedisce a un utente malintenzionato di dire facilmente se diversi utenti hanno la stessa password (il che renderebbe tali utenti target ovvio, dal momento che una password così comune sarebbe probabilmente facile da indovinare e fornire un elevato profitto).

  • Al contrario, impedisce anche a un utente malintenzionato che ha compromesso più siti di essere in grado di dire facilmente quali utenti hanno utilizzato la stessa password su entrambi i siti.

  • Inoltre, l'utilizzo di un unico sale per ogni utente impedisce a un utente malintenzionato di ottenere i vantaggi di any dall'attacco di più account contemporaneamente. Senza sali (o con sali non univoci), un utente malintenzionato potrebbe eseguire l'hashing di una password indovinata e confrontarla con ogni hash di password nel database, aumentando le probabilità che ottengano almeno una corrispondenza. Con sali unici, questo è impossibile, poiché l'attaccante deve scegliere il sale (e quindi un singolo utente target) prima di eseguire l'hashing di ogni password.

  • Infine, i sali unici rendono anche poco pratico l'uso di tabelle di ricerca hash precompilate (come le cosiddette "tabelle Rainbow") per accelerare il crack delle password, poiché, in sostanza, una tabella separata sarebbe necessaria per ogni utente.

Fondamentalmente, l'obiettivo principale della salatura è garantire che un crack di più hash di password compromessi insieme non sia più facile del crack di ciascuno di essi separatamente - niente di più e niente di meno. L'uso di sali unici a livello globale raggiunge questo obiettivo.


Un modo semplice per garantire l'unicità globale (con elevata probabilità) è utilizzare una stringa casuale sufficientemente lunga come sale. Tuttavia, esistono anche altri modi.

Ad esempio, potresti ottenere un salt unico a livello globale combinando un identificatore utente univoco locale (come un indirizzo e-mail o un numero di account) con un identificatore di sito fisso e univoco globale (ad esempio il nome di dominio di un sito Web), e possibilmente alcuni altri elementi come una designazione dello scopo (nel caso in cui potresti aver bisogno di più di un unico sale per utente) e un timestamp (quindi una nuova password riceverà sempre un sale diverso). Ad esempio, la seguente stringa sarebbe perfettamente valida in tutto il mondo:

"Questa è una password salt per l'utente 5457 su security.stackexchange.com creata il 1 settembre 2013 13: 35: 23.94730 UTC"

e così anche questo:

"Password_salt: 5457: security.stackexchange.com: 20130901T133523.94730"

Se preferisci che i tuoi sali siano più compatti, puoi anche alimentare una delle stringhe sopra attraverso un funzione di crittografia crittografica come SHA-256 e usare l'output come sale. Oppure, se il tuo sistema fornisce un generatore GUID incorporato, potresti semplicemente usarlo (supponendo che funzioni come dovrebbe, ovviamente).


Detto questo, c'è è un potenziale vantaggio nel rendere i sali delle password non solo unici ma anche imprevedibili: impedisce all'attaccante di iniziare un attacco a forza bruta prima hanno compromesso il tuo database.

Fondamentalmente, se io, come attaccante, sapevo che il sale del tuo account amministratore era, ad esempio, "12345678", allora avrei potuto impostare il mio computer (s) per compilare una tabella di ricerca di password più o meno comuni hash con quel salt anche prima che avessi trovato il modo di ottenere l'hash della tua password reale. Una volta trovato il modo di farlo (forse settimane o mesi dopo), ho potuto cercare l'hash nel mio tavolo, sperando che potesse corrispondere a una delle password che il mio programma aveva già provato nel frattempo, nel qual caso io conoscerebbe immediatamente la password.

Tuttavia, se non sapessi nemmeno quale fosse il vero sale che hai usato, non sarei in grado di iniziare a indovinare la password prima di ottenere il sale corretto. Ciò richiederebbe più tempo, potenzialmente permettendoti di cambiare la password prima che riuscissi a decifrarla.

Ancora una volta, i sali casuali lunghi sono (con alta probabilità) non solo unici ma anche imprevedibili. Detto questo, ci sono anche altri modi per raggiungere questo obiettivo. Ad esempio, potresti prendere uno dei sali di esempio univoci mostrati sopra e semplicemente aggiungere un valore segreto (ad esempio una stringa casuale memorizzata in un file di configurazione, eventualmente modificata regolarmente) ad esso. Poiché questo segreto sarebbe lo stesso per tutti gli utenti, non aiuterebbe con l'unicità, ma assicurerebbe che non sarei in grado di iniziare un attacco di forza bruta senza prima imparare in qualche modo il segreto.


Addendum: Per quanto riguarda le tue modifiche alla domanda, direi che il tuo schema (usando nome di dominio + ID utente + pepe come sale) dovrebbe essere sufficiente . Se possibile, includerei anche un timestamp, ma ciò ovviamente richiede che tu memorizzi il timestamp da qualche parte.

Detto questo, trovo ancora un po 'sconcertante la tua premessa ("il sale non è archiviato nel database"). Se riesci a memorizzare l'hash della password nel database, perché non anche Salt?

In effetti, molti schemi di hashing delle password comuni non usano affatto una colonna di database separata per il salt, ma lo memorizzano semplicemente come parte della stringa hash, ad es. come method$salt$hash, dove method identifica il metodo di hashing utilizzato, salt e hash sono i valori salt e hash codificati utilizzando uno schema adatto (ad esempio base64) e $ è solo un carattere di separazione arbitraria che non si presenta nel sale o nell'hash codificato.

10
Ilmari Karonen

Un sale dovrebbe essere unico, deve essere abbastanza lungo e dovrebbe essere imprevedibile. La casualità non è necessaria, ma è il modo più semplice per un computer di soddisfare tali requisiti. E non è lo scopo di un sale essere segreto, un sale adempie al suo scopo anche se noto.

nicità significa che non dovrebbe essere unico nel tuo database (altrimenti potresti usare un userid), dovrebbe essere unico in tutto il mondo. Qualcuno potrebbe creare rainbowtables per sali come ad es. 1-1000 e sarebbe in grado di recuperare le password per tutti gli account con quegli userid (spesso gli account admin hanno userid bassi).

Abbastanza lungo: Se il sale è troppo corto (troppo poche combinazioni possibili), diventa di nuovo redditizio costruire tavoli Rainbow. Salt e password insieme possono quindi essere visti come solo una password più lunga e se puoi creare una tabella Rainbow per queste password più lunghe, otterrai anche le password originali più brevi. Per password molto forti e lunghe, la salatura in realtà non sarebbe affatto necessaria, ma la maggior parte delle password generate dall'uomo può essere forzata perché sono brevi (le persone devono ricordarle).

Anche l'utilizzo di sali derivati ​​da altri parametri può rientrare in questa categoria. Solo perché si calcola un hash dall'ID utente, ciò non aumenta le possibili combinazioni.

Imprevedibilità è un po 'meno importante, ma immagina ancora una volta il caso in cui usi userid come sale, un utente malintenzionato può scoprire quali saranno i prossimi userid successivi e può quindi precalcolare un numero ristretto di Rainbow -Tavoli. A seconda dell'algoritmo hash utilizzato, questo può essere applicabile o meno. Ha un vantaggio temporale quindi, può recuperare immediatamente la password. Un problema maggiore sarà se gli account amministratore usavano un sale prevedibile.

Quindi usare un numero davvero casuale, generato dalla fonte casuale del sistema operativo (dev/urandom), è il massimo che puoi fare. Anche quando ignori tutti i motivi di cui sopra, perché dovresti usare un sale deragliato quando c'è un modo migliore, perché non usare il modo migliore che conosci?

AGGIORNAMENTO: per rispondere alla domanda modificata:

Usare solo domain_name + user_id per generare il salt non è sicuramente una buona idea, perché può essere indovinato e renderlo prevedibile. Un pepe non aiuta qui, perché è costante come domain_name, non dovresti fare affidamento su di esso per essere segreto. Con user_id ottieni unicità, con domain_name ottieni unicità globale, ma ti manca la parte imprevedibile.

Nel tuo esempio precedente hai aggiunto la password stessa come parametro casuale come salt = hash(domain_name + user_id + password). Questo potrebbe funzionare fintanto che il salt non sarà affatto memorizzato, per verificare la password avresti tutti i parametri necessari. Non riesco a vedere un difetto in questo concetto, ma questo non significa che lo consiglio. Come già accennato, non puoi fare di meglio che generare un sale indipendente casuale. Aggiungere questo sale all'hash ed estrarlo per la verifica non è un lavoro difficile, le funzioni hash più appropriate lo faranno già per te, perché devono anche memorizzare il fattore di costo allo stesso modo.

4
martinstoeckli

Prima di tutto, il mio motivo è di evitare di archiviare il sale nel database come testo normale.

Perché? Non vi sono buoni motivi per evitare di archiviare il sale nel database in testo semplice. Ecco come viene normalmente immagazzinato un sale.

Con le varie iterazioni della tua domanda, hai proposto vari modi per fare le cose in modo diverso, ma tutti finiscono per avere le stesse proprietà di sicurezza o (di solito) peggiorano le cose.

Il punto di forza è impedire agli aggressori di condividere il lavoro quando eseguono il cracking di molti account contemporaneamente. Spesso gli aggressori non cercano un determinato utente su un determinato sito, quello che vogliono è ottenere un punto d'appoggio o rompere il maggior numero possibile di account. Il punto è che rendere il cracking dell'account di Joe sul sito ACME richiede calcoli completamente diversi dal crack dell'account di Jane o di Joe sul sito Yoyodyne. Da qui la necessità che un sale sia univoco a livello globale: tra account e database (e anche nel tempo).

Se si utilizza la password come parte del calcolo del sale, non è affatto un sale. Il sale deve essere indipendente dalla password. Se calcoli il sale dalla password, allora diventa parte della funzione hash: H (S (P), P) è una funzione di P, hai solo creato una nuova funzione hash H '(P) = H ( S (P), P).

L'uso del nome utente non è buono perché può essere lo stesso nei database. Un utente malintenzionato con il database ACME e il database Yoyodyne può rompere entrambi i database senza duplicare lo sforzo se utilizzano il sale derivato dal nome utente.

Se usi il nome di dominio e l'ID utente, può funzionare. Assicurati che nessun altro al mondo utilizzi lo stesso nome di dominio; in particolare, non utilizzare lo stesso nome di dominio se si dispone di più di un sito secondario: includere il nome del servizio o qualunque cosa occorra per renderlo univoco. Inoltre, non riutilizzare gli ID utente. Finché il tuo sale è unico a livello globale, è un sale adeguato.

Si noti tuttavia che non si otterrà alcuna sicurezza dall'utilizzo del nome di dominio e dell'ID utente come salt piuttosto che come salt casuale come avviene normalmente. Il salt è ancora efficacemente archiviato nel database, solo in qualche modo strano. Si salva qualche byte per record di database, che non dovrebbe essere significativo.

Un pepe non migliora significativamente la sicurezza. Non puoi presumere che il tuo pepe rimanga segreto. Se l'aggressore è stato in grado di ottenere una copia del database delle password (in genere compromettendo l'applicazione o ottenendo l'accesso a un backup), è probabile che abbiano anche accesso al pepe (deve essere accessibile all'applicazione e supportato dopo tutto). L'unico caso in cui un pepe è utile è un compromesso come l'iniezione SQL che concede solo l'attaccante l'accesso al database e non si estende a un compromesso dell'applicazione, nemmeno tramite un account amministrativo. Non ci contare. Anche se usi un pepe, il tuo sale deve essere unico a livello globale .

Consiglio vivamente di generare un salt casuale e di memorizzarlo insieme alla password. Preferibilmente, non codificarlo tu stesso: usa una libreria esistente che lo fa nel modo giusto . Più si discosta dalla pratica raccomandata, più si rischia di sbagliare, forse completamente, pericolosamente sbagliato, come derivare il sale dalla password.

Ricorda che oltre ad essere salato, gli hash delle password devono essere lenti. Ciò significa che PBKDF2 o bcrypt o scrypt, con un conteggio delle iterazioni regolato per le velocità correnti del computer.

Per ulteriori informazioni, leggi i nostri numerosi thread su questo argomento:

Poiché nessuna delle altre risposte sembra toccarlo:

NON utilizzare parte della password come sale. Oltre a ridurre l'imprevedibilità, quando l'attaccante lo risolverà, aiuterà un aggressore a infrangere le password. Perché? Perché ne hanno parte proprio lì, accanto alla password nel database.

Aggiornamento: Se stai usando parte della password nel sale e vuoi evitare di dover conservare il sale, quindi tirare parte della password dopo averla inserita per calcolare il sale funzionerà bene. Inoltre complica la forza bruta ed è altrettanto efficace di un sale normale all'aumentare dell'entropia. Rende le tabelle Rainbow un po 'più difficili da realizzare, poiché è necessario calcolare il sale per password, ma non le impedisce davvero meglio di un normale sale.

2
demize

Oltre all'eccezionale risposta di @ terry-chia, c'è un altro motivo per scegliere sali casuali. Lo schema di hashing e autenticazione che stai utilizzando oggi può imporre requisiti relativamente deboli sulla salatura, ma un giorno potresti (o un successore) modificare lo schema utilizzato in un modo che ha un requisito di casualità.

Quindi, anche se la casualità non è un requisito, sei molto più sicuro se scegli sali casuali, poiché ciò garantirà che tu ottenga tutte le cose necessarie per il tuo schema oggi, ma ti fornirà anche ciò di cui potresti aver bisogno domani.

Ancora una volta, un motivo in più, oltre a ciò che altri hanno già spiegato. Non derivare il sale dai dati dell'utente! L'utilizzo di un sale casuale può farti ottenere più del necessario, ma ti garantirà di non commettere altri errori. Non hai nulla da guadagnare nel non usare un salt casuale (a meno che non ci sia qualcosa che non hai ancora spiegato), mentre rendi il tuo sistema molto meno robusto semplicemente andando per i requisiti minimi di un salt.

1