Это способ солить и сохранить пароль в Db?
Существуют разные способы (даже здесь, в SO), и все они упоминают, что лучший способ сохранить пароль в базе данных - это сохранить, а не пароль, а не пароль hased, но сохранить хэш соленых пароль.
Мой вопрос прост, вводя на него некоторый код, правильно ли это?
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
соленому, hased пароль, который был предоставлен.
Мое единственное беспокойство: это лучший способ солить пароль? Можно ли использовать созданную дату (так как это всегда будет изменяться, и я читаю, что лучше всего использовать всегда другой salt
каждый раз, когда мы кодируем пароль...
Или должна быть salt
совершенно другая переменная?
Ответы
Ответ 1
Ваша реализация, вероятно, достаточно хороша, но было бы лучше использовать соль с большей энтропией: значение тиков, которое вы сейчас используете, всегда будет в относительно небольшом диапазоне.
Я бы предложил использовать что-то вроде 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!");
}
Ответ 2
Мне интересно, почему никто не упомянул BCrypt. Существует готовая к использованию реализация для С#. См. http://derekslager.com/blog/posts/2007/10/bcrypt-dotnet-strong-password-hashing-for-dotnet-and-mono.ashx
Не изобретайте велосипед, если есть обоснованные решения для вашей проблемы.
Ответ 3
Ваш метод полностью прекрасен, но пусть кто-то получил вашу базу данных, но не вашу базу кода. Они могли бы по существу выяснить, что вы просто конкатенировали пароль и создали дату, и они могли перепрограммировать все пароли.
Возможно, вы захотите добавить уникальную строку, которая существует только в вашей базе кода, для небольшой дополнительной защиты.
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
}
Ответ 4
Как насчет того, чтобы попробовать: ProtectedData.Protect
метод?
Этот метод может использоваться для шифрования данных, таких как пароли, ключи или строки подключения. Параметр optionalEntropy позволяет добавлять данные для увеличения сложности шифрования; укажите null для дополнительной сложности. Если предоставлено, эта информация также должна использоваться при дешифровке данных с использованием метода Unprotect.
Ответ 5
Я думаю, что идея с 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){ ... }