Проверка соленого хэша

Я новичок в C#, и это мой первый вопрос здесь, поэтому я заранее извиняюсь за любые faux pas.

контекст:

когда пользователь регистрируется, я вызываю метод CreateSaltedHash () и передаю ему введенный пользователем пароль из текстового поля. Этот метод солит и хэширует пароль, прежде чем хранить его в столбце пароля моей таблицы пользователей.

вопрос:

Как я должен проверить пароль, когда пользователь пытается войти в систему?

Если я снова вызову метод CreateSaltedHash (), он не будет совпадать из-за случайной соли.

должен ли я хранить соли в отдельной колонке? Должен ли я использовать разделитель при создании соленого хэша? Каков наиболее безопасный способ проверки входного пароля против соленого и хэшированного пароля?

код: Это то, что у меня есть до сих пор.

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.
    }
}


Вызов метода в регистре класс.

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

10 ответов


когда вы впервые генерируете хэш, вам нужно сохранить как соль, так и окончательный хэш, а затем повторно использовать ту же соль для будущих сравнений.

таким образом, вы измените свой CreateSaltedHash метод, чтобы взять пароль и соль, и написать новый CreateSalt метод для генерации соли при создании/изменении пароля, который хранится вместе с окончательным хэшем.


вы можете использовать Bcrypt.Net; у него есть много рекомендаций для того, чтобы быть действительно безопасным, плюс он очень прост в использовании. Насколько я понимаю, при создании пароля он автоматически генерирует уникальную соль для вас, которая затем сохраняется в строке хэшированного пароля; поэтому вы не храните соль отдельно, а в том же поле, что и хэшированный пароль. Дело в том, что каждый пароль имеет свою собственную соль, что делает его гораздо более сложным (трудоемким) для хакера несколько паролей. Алгоритм, используемый Bcrypt, также интенсивен для процессора, поэтому для взлома требуется много вычислительной мощности (=деньги).

Джефф Этвуд (модератор stackoverflow) рекомендует Bcrypt.


вам придется хранить соль вместе с хэшем.

обратитесь к этой статье, чтобы получить некоторую справочную информацию: http://www.h-online.com/security/features/Storing-passwords-in-uncrackable-form-1255576.html


Как говорится в других ответах; Да, вы должны хранить соль или выводить ее, например, из имени пользователя.

вы должны использовать Rfc2898DeriveBytes чтобы сделать его более безопасным.

вот хорошая статья на эту тему: соль пароля и хэширование в C#


Я предлагаю вам использовать SaltedHash ServiceStack, который вы можете установить из своего Nuget. Просто Введите Install-Package ServiceStack в консоли Nuget, то вы сможете использовать следующие импорта в коде.

using ServiceStack.ServiceInterface.Auth;

и тогда вы бы генерировать соль и хэш так много легче абсолютно быстрее чем раньше. Просто введите следующие коды:

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

и да необходимо магазине хэш и соль чтобы иметь возможность запускать метод OkPassword.

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

должен ли я хранить соли в отдельной колонке?

да.

должен ли я использовать разделитель при создании соленого хэша?

Не обязательно, но это также не повредит, пока вы включаете тот же разделитель при проверке.

каков наиболее безопасный способ проверки входного пароля против соленого и хэшированного пароля?

криптография SHA512, ша-2 или -3 будет будьте более безопасны, чем SHA256, но вам нужно гораздо больше безопасности?


вы можете либо хранить соль, либо использовать одну и ту же соль каждый раз. Я рекомендую хранить соль, поскольку она более безопасна, чем использование одной и той же соли для всех пользователей.

в большинстве моих таблиц есть столбец с датой создания строки. Я использую свойство Ticks DateTime структура этого значения для соли хэша, но вы можете использовать все, что угодно, если вы используете одну и ту же соль для пользователя каждый раз. Одна вещь, чтобы следить за, если вы используете этот метод, и вы используете тип SQL DateTime (а не DateTime2), тогда возникает проблема точности. Если вы создадите DateTime в коде, вам нужно будет обрезать его (я считаю до сотых секунды).


и для более длинного ответа -

has должен быть случайным с каждым созданным паролем. Это сделает его уникальным. Из-за этой "случайности" вы почти никогда не сможете программно найти хэш, связанный с файлом.

способ шифрования пароля (без хэша) должен быть одинаковым, поэтому использование обратного этого метода будет достаточным каждый раз.
PS:(более безопасный способ проверки) вы можете либо обратного зашифрованный пароль к его оригиналу [жесткий], или зашифровать пароль проверки с хэшем, и убедитесь, что зашифрованный пароль соответствует, который хранится в DB [предпочтительным].

Итак, вам нужно будет сохранить зашифрованный пароль, а также хэш, связанный с ним, в базе данных.

Это будет способ собрать всю информацию, необходимую для проверки пароля.


поскольку вы генерируете случайную соль, вам нужно будет сохранить соль в базе данных. Проблема в том, что если ваша база данных будет скомпрометирована, злоумышленник будет иметь соль и хэшированный пароль, поэтому они могут легче определить реальный пароль. В идеале у вас должна быть статическая соль в коде, так что если ваша база данных скомпрометирована, у них все еще нет соли, и если ваш код скомпрометирован, у них нет базы данных просто еще.

другим решением может быть использование перца. Перец похож на соль, но вы не храните его в базе данных с солью и хэшированным паролем. Он будет храниться в коде. Таким образом, у вас есть случайная соль, которая генерируется, и константа, которая хранится отдельно. Чтобы сделать перец более случайным, вы можете создать подстроку большей строки, которую вы используете для перца, который смещается на основе некоторой переменной, такой как идентификатор пользователя. Это опять-таки внутренняя вещь, которая атака не будет знать, если им удалось получить ваши данные.


вы должны сохранить дайджест и соль. Итерации и значения digestLength могут быть константами в вашем приложении.

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);
}

недавние статьи предполагают, что для дальнейшей защиты паролей вы можете разделить пароль на части, хэшировать отдельные части, а затем хранить их в отдельных таблицах в БД.