2012-11-15 16 views
9

Sono nuovo di C# e questa è la mia prima domanda qui, quindi mi scuso in anticipo per qualsiasi passo falso.Convalida un hash salato

Contesto:

Quando un utente si registra chiamo il metodo CreateSaltedHash() e passano la password immessa utente dal campo di testo. Questo metodo salina e cancella la password prima di memorizzarla nella colonna Password della mia tabella Utente.

Domanda:

Come devo convalidare la password quando un utente tenta di accedere?

Se chiamo di nuovo il metodo CreateSaltedHash(), esso non corrisponderà a causa del sale casuale.

Devo conservare i sali in una colonna separata? Dovrei usare un delimitatore quando si genera l'hash salato? Qual è il modo più sicuro di convalidare la password di input con la password salata e con hash?

Codice: Questo è quello che ho finora.

public class PasswordHash 
{ 
    public const int SALT_BYTES = 32; 

    /* 
    * Method to create a salted hash 
    */ 
    public static byte[] CreateSaltedHash(string password) 
    { 
     RNGCryptoServiceProvider randromNumberGenerator = new RNGCryptoServiceProvider(); 
     byte[] salt = new byte[SALT_BYTES]; 
     randromNumberGenerator.GetBytes(salt); 
     HashAlgorithm hashAlgorithm = new SHA256Managed(); 
     byte[] passwordByteArray = Encoding.UTF8.GetBytes(password); 
     byte[] passwordAndSalt = new byte[passwordByteArray.Length + SALT_BYTES]; 
     for (int i = 0; i < passwordByteArray.Length; i++) 
     { 
      passwordAndSalt[i] = passwordByteArray[i]; 
     } 
     for (int i = 0; i < salt.Length; i++) 
     { 
      passwordAndSalt[passwordByteArray.Length + i] = salt[i]; 
     } 
     return hashAlgorithm.ComputeHash(passwordAndSalt); 
    } 

    public static bool OkPassword(string password) 
    { 
     //This is where I want to validate the password before logging in. 
    } 
} 


Chiamando il metodo nella classe Register.

User user= new User(); 
user.password = PasswordHash.CreateSaltedHash(TextBoxUserPassword.Text); 
+0

'Devo conservare i sali in una colonna separata? - Sì. Quindi fare riferimento a questo. – TheGeekZn

+0

Capisci che c'è un problema serio con il tuo metodo di hashing giusto? Dovresti davvero usare un algoritmo hasing per proteggere le password, la tua scelta attuale non è una buona scelta. –

+0

Ho modificato il tuo titolo. Per favore vedi, "[Le domande dovrebbero includere" tag "nei loro titoli?] (Http://meta.stackexchange.com/questions/19190/)", dove il consenso è "no, non dovrebbero". –

risposta

1

prima volta che si genera l'hash, è necessario memorizzare sia il sale e l'hash finale - poi ri-utilizzare lo stesso sale per i confronti futuri.

Così si modifica il metodo CreateSaltedHash per prendere una password e una salt e si scrive un nuovo metodo CreateSalt per generare il salt quando viene creata una password, che viene memorizzata insieme all'hash finale.

0

Devo conservare i sali in una colonna separata?

Sì.

Devo utilizzare un delimitatore durante la generazione dell'hash salato?

Non necessario, ma non guasta se si include lo stesso delimitatore durante la convalida.

Qual è il modo più sicuro di convalidare la password di input con la password salata e con hash?

SHA512, SHA-2 o -3 sarebbero più sicuri di SHA256, ma è necessaria molta più sicurezza?

0

È possibile memorizzare il sale, o utilizzare lo stesso sale ogni volta. Raccomando di conservare il sale in quanto è più sicuro rispetto all'utilizzo dello stesso sale su tutti gli utenti.

La maggior parte delle mie tabelle ha una colonna con la data della data di creazione della riga. Io uso la proprietà Ticks della struttura DateTime di questo valore per salare l'hash, ma puoi usare qualsiasi cosa tu voglia, a patto che tu usi sempre lo stesso sale per l'utente. Una cosa a cui prestare attenzione è se si utilizza questo metodo e si utilizza il tipo SQL DateTime (e non DateTime2), quindi c'è un problema di precisione. Se si crea il codice DateTime nel codice, sarà necessario troncarlo (credo per un centesimo di secondo).

0

E per la risposta più -

L'ha dovrebbe essere casuale con ogni password creata. Questo lo renderà unico in sé. A causa di questa "casualità", non sarà quasi mai possibile trovare l'hash associato al file in modo programmatico.

Il modo in cui è stata crittografata la password (senza l'hash) dovrebbe essere la stessa, quindi l'utilizzo di un metodo inverso rispetto a questo metodo sarà sempre sufficiente.
PS: (un modo più sicuro o validazione) Si può o invertire la password criptata al suo originale [Disco], o cifrare la password convalidare con l'hash, e fare in modo che la password crittografata corrisponde a quello memorizzato nel DB [preferito].

Quindi, sarà necessario memorizzare la password crittografata, nonché l'hash ad esso associato, nel database.

Questo sarà il modo per raccogliere tutte le informazioni necessarie per convalidare la password.

0

Poiché si genera un salt casuale, è necessario memorizzare il sale nel database. Il problema è che se il database viene compromesso, l'utente malintenzionato avrà la password salt e hash, in modo che possano determinare più facilmente la password reale. Idealmente dovresti avere un sale statico nel tuo codice in modo che se il tuo database è compromesso non hanno ancora il sale e se il tuo codice è compromesso, non hanno ancora il database.

Un'altra soluzione potrebbe essere l'uso di pepe. Pepper è simile al sale ma non lo memorizza nel database con la password salt e hash. Sarebbe memorizzato nel codice. In questo modo si ha un sale casuale generato e una costante che viene memorizzata separatamente. Per rendere il pepe più casuale, è possibile creare una sottostringa di una stringa più grande che si sta utilizzando per un pepe, che è l'offset basato su alcune variabili, come l'id utente. Questa è di nuovo una cosa interna di cui un attacco non sarebbe a conoscenza se riuscissero a ottenere i tuoi dati.

+1

Se si dispone di un diverso, unico sale per ogni password, quindi diventa molto più difficile per un hacker per crack più passord. – Polyfun

+0

Sì, ma è necessario memorizzare i sali unici da qualche parte, se sono sul database allora l'hacker li avrà in modo tale che il fatto che siano diversi è irrilevante. –

+3

Non è così, perché se i sali sono unici, diventa molto più costoso crackare più password, specialmente usando qualcosa come bcrypt - per favore vedi http://www.codinghorror.com/blog/2012/04/speed-hashing.html . – Polyfun

1

Come le altre risposte; sì, dovresti conservare il sale o derivarlo, ad esempio dal nome utente.

È inoltre necessario utilizzare Rfc2898DeriveBytes per renderlo più sicuro.

Ecco un buon articolo su questo argomento: Password salt and hashing in C#

3

si potrebbe usare Bcrypt.Net; ha molte raccomandazioni per essere davvero sicuro, inoltre è molto facile da usare.A quanto ho capito, quando crei la password, genera automaticamente un sale unico per te, che viene quindi memorizzato nella stringa della password con hash; quindi non si memorizza il sale separatamente, ma nello stesso campo della password con hash. Il punto è che ogni password ha il proprio sale, il che rende molto più difficile (in termini di tempo) per un hacker di crackare più password. L'algoritmo utilizzato da Bcrypt ha anche un utilizzo intensivo della CPU, pertanto richiede molta potenza di calcolo (= denaro) da decifrare.

Jeff Atwood (moderatore stackoverflow) recommends Bcrypt.

0

È necessario salvare il digest e il sale. I valori iterazioni e digestLength possono essere costanti nell'applicazione.

byte[] getNewSalt(Int32 size) 
{ 
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
    byte[] salt = new byte[size]; 
    rng.GetBytes(salt); 
    return salt; 
} 


byte[] getPasswordDigest(byte[] value, byte[] salt, Int32 iterations, Int32 digestLength) 
{ 
    Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(value, salt, iterations); 
    return deriveBytes.GetBytes(digestLength); 
} 

articoli recenti suggeriscono che per le password più sicure, è possibile dividere la password in parti, hash le singole parti, poi memorizzarli in tabelle separate nel DB.

1

I Suggerisco di utilizzare SaltedHash di ServiceStack che è possibile installare dal Nuget. Inserire semplicemente Install-Package ServiceStack nella console Nuget, quindi sarà possibile utilizzare le seguenti importazioni nel codice.

using ServiceStack.ServiceInterface.Auth; 

E allora si sarebbe generare il sale e hash molto più facile e assolutamente veloce rispetto a prima. Basta inserire i seguenti codici:

class Security 
{ 
    ... 
    public void generate(string Password) 
    { 
    string hash, salt; 
    new SaltedHash().GetHashAndSaltString(Password,out hash,out salt); 
    //Store the hash and salt 
    } 
    ... 
} 

E , è necessario negozio l'hash e sale per essere in grado di eseguire il metodo OkPassword.

public bool OkPassword(string Password) 
{ 
    var hash = //getStoredHash 
    var salt = //getStoredSalt 
    bool verify = new SaltedHash().VerifyHashString(Password, hash , salt); 
    return verify ; 
}