Это способ солить и хранить пароль в БД? - PullRequest
13 голосов
/ 25 марта 2011

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

Мой вопрос прост: на нем есть код, это правильный путь?

string username = "myUsr";
string password = "myPwd";
DateTime createDate = DateTime.UtcNow;

// Salt it
string saltedPwd = String.Concat(password, createDate.Ticks.ToString());

// Hash it
HMACSHA1 hash = new HMACSHA1(Encoding.Unicode.GetBytes(Helper.EncryptKey));
string encodedPwd = Convert.ToBase64String(
                        hash.ComputeHash(Encoding.Unicode.GetBytes(saltedPwd)));

// Create User in the database
db.CreateUser(username, encodedPwd, createDate);

Таблица пользователей базы данных

user_id | username | password | create_date | last_access | active

и при входе в систему выполните процедуру еще раз и проверьте, совпадает ли encodedPwd с соленым, затененным паролем, который был предоставлен.

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

Или salt должна быть совершенно другой переменной?

Ответы [ 5 ]

18 голосов
/ 25 марта 2011

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

Я бы предложил использовать что-то вроде PBKDF2 , чтобы выполнить работу за вас, через Rfc2898DeriveBytes:

string username = "myUsr";
string password = "myPwd";

using (var deriveBytes = new Rfc2898DeriveBytes(password, 20)) // 20-byte salt
{
    byte[] salt = deriveBytes.Salt;
    byte[] key = deriveBytes.GetBytes(20); // 20-byte key

    string encodedSalt = Convert.ToBase64String(salt);
    string encodedKey = Convert.ToBase64String(key);

    // store encodedSalt and encodedKey in database
    // you could optionally skip the encoding and store the byte arrays directly
    db.CreateUser(username, encodedSalt, encodedKey);
}

И для аутентификации ...

string username = "myUsr";
string password = "myPwd";

string encodedSalt, encodedKey;
// load encodedSalt and encodedKey from database for the given username
byte[] salt = Convert.FromBase64String(encodedSalt);
byte[] key = Convert.FromBase64String(encodedKey);

using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
    byte[] testKey = deriveBytes.GetBytes(20); // 20-byte key

    if (!testKey.SequenceEqual(key))
        throw new InvalidOperationException("Password is invalid!");
}
4 голосов
/ 25 марта 2011

Мне интересно, почему никто еще не упомянул BCrypt . Есть готовая к использованию реализация для C #. Смотри http://derekslager.com/blog/posts/2007/10/bcrypt-dotnet-strong-password-hashing-for-dotnet-and-mono.ashx

Не изобретайте велосипед, если для вашей проблемы есть проверенные решения.

0 голосов
/ 25 марта 2011

Я думаю, что идея с CreateDate является достаточно мощной, но когда кто-то крадет вашу БД и код, ваша соль раскрывается.Безопасность, основанная на том, что «никто не может взломать мой код» - это плохая безопасность.

Вы можете просто дважды хешировать пароль ... И использовать соль с первого хэширования.

string Flavor(string passwd)
{
   string fhash = Str2SHA1(passwd);
   string salt = fhash[2] + fhash [10] + fhash[1]; // or whatever...
   string realhash = Str2SHA1(hash + salt);
}
string Str2Sha1(string str){ ... }
0 голосов
/ 25 марта 2011

Как вы можете попробовать: ProtectedData.Protect метод?

Этот метод может использоваться для шифрования таких данных, как пароли , ключи или соединениестроки.Параметр optionEntropy позволяет добавлять данные для повышения сложности шифрования ;укажите ноль без дополнительной сложности.Если предоставлено, эта информация также должна использоваться при расшифровке данных с использованием метода Unprotect.

0 голосов
/ 25 марта 2011

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

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

string username = "myUsr";
string password = "myPwd";
DateTime createDate = DateTime.UtcNow;

// Salt it
string saltedPwd = String.Concat(password, SomeOtherClass.StaticKey, createDate.Ticks.ToString());

public class SomeOtherClass
{
    public static string StaticKey = "#$%#$%superuniqueblahal$#%@#$43580"; // should probably be const/readonly, but whatever
}
...