HashPasswordForStoringInConfigFile - различные хеши для одного и того же пароля
Недавно я реализовал хеширование своих паролей в проекте, над которым я работаю, и я не могу понять, что происходит не так.
Похоже, что функция HashPasswordForStoringInConfigFile() возвращает разные значения для одного и того же пароля.
У меня есть следующий реализованный код, который на самом деле очень похож на рекомендуемый алгоритм для использования в документации MSDN.
Я знаю, что хеширование SHA1 не считается очень безопасным, но это для исследовательского применения, и я не слишком беспокоюсь об этом в данный момент.
public const int DefaultSaltSize = 5;
private static string CreateSalt()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[DefaultSaltSize];
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
public static string CreateHash(string password)
{
string salt = CreateSalt();
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword,"SHA1");
hashedPassword = string.Concat(hashedPassword,salt);
return hashedPassword;
}
public static bool VerifyPassword(string username, string password,AccountDataContext context)
{
var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
if (user != null)
{
string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
string hashedPassword = CreateHash(password);
return hashedPassword.Equals(user.Password);
}
return false;
}
Проще говоря, если у меня есть следующий код.
string password1 = "password";
string password2 = "password";
var hashedPassword1 = CreateHash(password1);
var hashedPassword2 = CreateHash(password2);
var match = hashedPassword1.Equals(hashedPassword2);
//match should be True, but it is turning out False.
Похоже, что FormsAuthenticationForStoringInConfigFile() не возвращает одинаковый хэш для password1 и password2 в методе CreateHash().
Я понимаю, что с примененной солью они не одинаковы, но если вы видите в коде, я удаляю соль, прежде чем сравнивать два hashedPasswords на равенство.
Что может быть причиной хэширования password1 и password2 по-разному?
3 ответа
Ваш код добавил соль (случайное значение) к паролю перед хэшированием. Это хорошая вещь.
Это означает, что если пользователь A и пользователь B используют один и тот же пароль, хэши паролей, тем не менее, будут разными.
Ваш метод VerifyPassword не использует исходную соль для хеширования пароля для сравнения - вместо этого он вызывает CreateHash
, который вызывает CreateSalt
и создает новую соль.
Вы можете попробовать что-то вроде:
public static string CreateHash(string password)
{
return CreateHash(password, CreateSalt());
}
private static string CreateHash(string password, string salt)
{
string saltAndPassword = String.Concat(password, salt);
string hashedPassword =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPassword,"SHA1");
hashedPassword = string.Concat(hashedPassword,salt);
return hashedPassword;
}
public static bool VerifyPassword(string username,
string password,AccountDataContext context)
{
var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
if (user != null)
{
string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
string hashedPassword = CreateHash(password, salt);
return hashedPassword.Equals(user.Password);
}
return false;
}
Несмотря на то, что VerifyPassword выглядит так, как будто он удаляет соленую часть нехэшированной строки, но код, который вы должны вернуть true, на самом деле не вызывает VerifyPassword.
Ваш код просто генерирует два соленых хэша, а затем использует String.Equals для их сравнения.
Что происходит, когда вы используете VerifyPassword вместо String.Equals?
Этот код тоже не работает вообще. Почему он помечен как правильный ответ?
Длина соли по умолчанию установлена на 5
Создайте Salt, когда он берет 5-байтовый массив в строку, он становится 8 символами, а не 5
В этом случае пароль подтверждения снимает только 5 символов для соли, а не 8, поэтому проверка всегда завершится неудачей, поскольку для соли используется 5 символов, а не 8, которые использовались для создания хешированного пароля.
Ниже приведен обновленный код для обеспечения работы вышеуказанного кода.
private const int DEFAULT_SALT_SIZE = 5;
private static string CreateSalt()
{
RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
byte[] buffer = new byte[DEFAULT_SALT_SIZE];
rngCryptoServiceProvider.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
public static string CreateHash(string password)
{
return CreateHash(password, CreateSalt());
}
private static string CreateHash(string password, string salt)
{
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
hashedPassword = string.Concat(hashedPassword, salt);
return hashedPassword;
}
public static bool VerifyPassword(string userpassword, string password)
{
byte[] bytePassword = Convert.FromBase64String(userpassword);
byte[] byteSalt = new byte[DEFAULT_SALT_SIZE];
Array.Copy(bytePassword, bytePassword.Length - DEFAULT_SALT_SIZE, byteSalt, 0, DEFAULT_SALT_SIZE);
string salt = Convert.ToBase64String(byteSalt);
string hashedPassword = CreateHash(password, salt);
return hashedPassword.Equals(userpassword);
}
Вот как я это назвал.
string hashedPassword = Security.CreateHash("password");
if (Security.VerifyPassword(hashedPassword, "password"))
{
Response.Write("Valid");
}
else
{
Response.Write("Not Valid");
}
Пока пароли совпадают, он возвращает true, в противном случае он возвращает false.
Это дает вам то, что, как я думаю, было предназначено, которое должно было не только включать соль внутри хеша, но и добавлять его к внешней стороне хеша, чтобы все это можно было сохранить в виде значения 1 столбца в базе данных, а затем использовать для воссоздания хеша. на введенный пользователем пароль, используя сохраненное значение соли и получить совпадение.