Come posso essere sicuro con un sale globale?

10

Se ho compreso le nozioni fondamentali sull'hash e sull'archiviazione delle password, ciò di cui abbiamo bisogno sono:

  1. un "strong" sale
  2. un "vero" sale casuale
  3. un unico salt per password
  4. una funzione hashing password con un elevato costo della CPU

Abbiamo cancellato le password utilizzando 1, 2, 3 e 4 utilizzando PHP crypt() e CRYPT_BLOWFISH con un costo "medio".

Abbiamo una nuova esigenza: dobbiamo essere in grado di confrontare gli hash perché abbiamo notato che le frodi / spam / truffatori di basso livello utilizzano le stesse password. Non è necessario conoscere la password di un utente abusivo ma solo sapere che un profilo sta utilizzando la stessa password di un utente abusivo precedentemente identificato.

Quindi stiamo pensando di avere 2 campi nel nostro database:

  • passwordA: usato per la procedura di login (questo campo userebbe 1, 2, 3 e 4)

crypt($password, '$2y$06$' . $uniqueSalt);

  • passwordB: usato per "confrontare" (questo campo vorremmo 1, 2 e 4)

crypt(md5(md5($password) . $globalSaltA) . $globalSaltB, '$2y$10$' . $globalSaltC);

I sali globali A e B verrebbero memorizzati solo nel codice dell'applicazione.

Per compensare il punto mancante 3 per passwordB, abbiamo aumentato il "costo" che è molto più alto.

Seguendo il commento, ho capito che questa strategia non è sicura se un utente malintenzionato riceve un accesso completo (database + codice) sul server. Tuttavia, se l'hacker ottiene solo il database, stiamo bene.

Le aziende che rilevano le frodi con carta di credito hanno lo stesso problema con i numeri delle carte di credito. Non possono memorizzarli ma devono confrontarli.

Quindi quale strategia / soluzione consiglieresti?

    
posta Toto 07.10.2013 - 16:33
fonte

4 risposte

12

Il problema principale: se il tuo server può confrontare in modo efficiente una password con hash con (potenzialmente) tutte le password con hash per tutti gli utenti, quindi anche un utente malintenzionato. Un utente malintenzionato che raccoglie una copia dei file / database del server sarà in grado di eseguire un attacco di dizionario offline, ovvero hashing password potenziale e cercare una corrispondenza.

L'hashing della password normale utilizza una password per salt per prevenire attacchi paralleli: vogliamo che l'attaccante paghi il prezzo computazionale completo della funzione hash (che è costosa in molte iterazioni) per ogni password e ogni account utente. Tuttavia, se diversi hash delle password utilizzano lo stesso salt, l'attacker può provare una potenziale password contro tutti per il costo di una chiamata di funzione hash. Quindi, il tuo "sale globale" indebolisce sostanzialmente lo schema: consente all'attaccante di attaccare 1000 account per il costo di attaccarne uno.

Il punto importante: il tuo problema è di temporalità. In effetti, in realtà non si desidera confrontare una nuova password utente con tutte le password di tutti gli altri utenti; ciò che si desidera è confrontare la password scelta da ciascun utente al momento della registrazione con un elenco limitato di "password dei trasgressori noti". Sfortunatamente, quando un utente registrato cade nello stato di "trasgressore", è già registrato e la sua password non è stata mantenuta in giro, solo l'hash di ciò. Quindi, davvero, ti piacerebbe poter accedere alla password utilizzata per la registrazione dopo la registrazione è avvenuta.

Una possibile soluzione: utilizzare l'impegno, alias crittografia asimmetrica . Creare una coppia di chiavi RSA. Archivia la chiave pubblica sul server. NON memorizzare la chiave privata corrispondente sul server; invece, memorizzalo altrove, ad es. su un laptop che è tenuto offline (o forse solo su alcune unità flash USB).

Quando un utente si registra, usa la sua password come al solito (con PBKDF2, molte iterazioni, un nuovo salt random, ecc.). Ma, anche, crittografare la password (non l'hash) con la chiave RSA e memorizzare il risultato della crittografia nel database, insieme all'hash. La crittografia richiede solo la chiave pubblica ed è randomizzata, quindi questa versione crittografata non fornisce ulteriore leva a un utente malintenzionato che ottiene una copia del contenuto del database. Quando un utente accede, l'hash della password viene utilizzato, come al solito.

Quando un utente risulta essere uno spammer, ottiene la chiave privata e decrittografa la password di deposito. In questo modo, ottieni la "password errata" e puoi aggiungerla all'elenco delle password da rifiutare al momento della registrazione. Tale elenco può essere mantenuto come testo chiaro: poiché i conti corrispondenti sono stati chiusi, non vi è alcun problema con questo. Fai attenzione a decifrare su una macchina "sicura", preferibilmente offline: non vuoi davvero vedere rubata la chiave privata.

Una parola di cautela: gli spammer sono come i batteri, in quanto tendono ad evolversi rispetto ai vincoli esterni. Se si escludono gli spammer in base alla loro abitudine di riutilizzare le password per la registrazione, verranno presto addestrate a generare password casuali. Quindi, prevedo che se si installa un tale sistema, cesserà di essere efficace nel respingere gli spammer dopo un tempo relativamente breve; dopo di ciò, sarà semplicemente un peso morto nel tuo database (non molto, perché un breve messaggio crittografato con RSA con una chiave RSA a 2048 bit è solo 256 byte, ma è comunque senza peso).

    
risposta data 10.10.2013 - 01:06
fonte
3

Non puoi. Annulla la sicurezza di avere un sale unico (o qualsiasi sale per quella materia) interamente. Il punto di avere un sale unico è che impedisce l'uso di una tabella arcobaleno per identificare la password. La memorizzazione con un punto globale consente di attaccare la tabella con una tabella arcobaleno e molto probabilmente identificherà la password originale in molti casi.

L'alternativa a questo è di generare un elenco di sali per provare una nuova password (quelli associati ai precedenti spammer). Rende la creazione di un nuovo utente un'operazione leggermente più difficile dal momento che è necessario eseguire l'hash della password più volte, tuttavia è l'unico modo sicuro per fare ciò di cui si sta parlando. La creazione di nuovi utenti dovrebbe anche essere l'unica volta in cui è necessario fare questo passaggio, quindi non dovrebbe essere troppo, troppo grande di un successo. Raccomanderei anche di farlo solo quando altri indicatori sembrano supportarlo come utente di spam se vuoi ridurre ulteriormente l'impatto.

Potresti anche memorizzare password errate dopo essere state identificate per mantenere l'elenco breve. Ad esempio, l'utente precedente con salt 1234 aveva un hash abcd. Quando un nuovo utente invia la password "ImSpam" e la si prova contro salt 1234, si vede che è abcd e ora conosce la password effettiva per quel salt, in modo da poter smettere di controllarlo e solo non consentire la password interamente. Questo dovrebbe mantenere la lista relativamente breve. Potresti anche invecchiare potenzialmente i vecchi utenti di spam dal momento che se non sei stato attaccato da quello spammer in un momento, è probabile che abbiano rinunciato.

    
risposta data 07.10.2013 - 16:48
fonte
0

Consente di chiamare gli hash salati in modo univoco "meglio" e gli hash globali / singolarmente salati "peggio". Per motivi di prestazioni, potresti voler mantenere gli hash migliori sul database degli utenti in modo da poter autenticare rapidamente gli utenti. Ti consigliamo di spostare gli hash "peggiori" su un server diverso e più sicuro con un'interfaccia sottile, semplice e autenticata composta da due metodi, AddPassword (userId, password) e Blacklist (spammerUserId).

AddPassword segnalerebbe semplicemente il successo o l'insuccesso. La lista nera aggiunge l'ID dello spammer alla lista nera e restituisce un elenco di tutti i UserId che corrispondono alla password dello spammer. Ma attenzione: chiunque abbia accesso può eseguire un dizionario contro il metodo Blacklist, avvelenando utenti legittimi e ottenendo elenchi di password corrispondenti.

Internamente, puoi memorizzarli come vuoi: hash, salato, crittografato o chiaro. Devi solo tenere la macchina bloccata in modo sicuro.

    
risposta data 09.10.2013 - 01:12
fonte
0

Come già detto @AJHenderson, la semplice risposta è che non è possibile. Capisci perché è necessario un sale unico e non ti stai perdendo alcun trucco matematico per questo, è davvero impossibile in combinazione con un sale unico. Detto questo, questo è il modo in cui risolverei il problema:

1. Vorrei aggiungere un nuovo campo di database chiamato qualcosa come UnsaltedPassword e riempirlo con tutti i valori NULL. Ogni volta che qualcuno registra o modifica la sua password, riempila con un hash della password, solo senza sale e dieci volte più strong dell'altro metodo di hashing.

2. Modificare la procedura di accesso in modo da verificare se l'utente ha un valore NULL in quel campo e, se l'utente lo fa, riempire il campo. Se ciò comportasse un carico eccessivo, esegui la funzione di hashing solo per determinati account, come ad esempio persone con un post-conto basso o semplicemente per caso (ad esempio, esegui l'hash con una possibilità di 1 su 10).

3. Infine, aggiungerei il controllo delle password duplicate ogni volta che il campo è compilato e anche il confronto con una lista nera. Le persone con i duplicati potrebbero essere contrassegnate (probabilmente anche detto che usano una password debole), e la lista nera viene immediatamente bannata (o inferta, se possibile).

Le modifiche alle password non avvengono spesso rispetto agli accessi (tutte le volte che è necessario eseguire l'altra funzione hash con salt), quindi penso che abbia senso avere due campi hash diversi in il database per scopi diversi. Anche un dieci volte più strong dovrebbe essere fattibile, o forse si potrebbe fare ancora di più (da 1 a 2 secondi tempo di hashing è quello a cui mirerei dato che è praticamente un affare da una sola volta). Probabilmente è più costoso per gli aggressori rompere questi problemi piuttosto che applicare il sale unico.

    
risposta data 09.10.2013 - 23:04
fonte

Leggi altre domande sui tag