Я работаю над реализацией безопасности в приложении ASP.NET MVC 3 и использую реализацию BCrypt , найденную здесь , для обработки шифрования и проверки паролей. Экран регистрации пользователя зашифровывает пароль, который пользователь предоставляет, и хешированный пароль сохраняется в базе данных. У меня проблема с проверкой пароля на странице входа в систему, и я не могу понять, почему.
Мое действие контроллера регистрации содержит следующее:
[HttpPost]
[RequireHttps]
public ActionResult Register(Registration registration)
{
// Validation logic...
try
{
var user = new User
{
Username = registration.Username,
Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)),
EmailAddress = registration.EmailAddress,
FirstName = registration.FirstName,
MiddleInitial = registration.MiddleInitial,
LastName = registration.LastName,
DateCreated = DateTime.Now,
DateModified = DateTime.Now,
LastLogin = DateTime.Now
};
var userId = _repository.CreateUser(user);
}
catch (Exception ex)
{
ModelState.AddModelError("User", "Error creating user, please try again.");
return View(registration);
}
// Do some other stuff...
}
Это пароль. Хэш:
public static string Hash(string password)
{
return BCrypt.HashPassword(password, BCrypt.GenerateSalt(12));
}
Вот так я обрабатываю логин:
[HttpPost]
[RequireHttps]
public ActionResult Login(Credentials login)
{
// Validation logic...
var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password);
if (authorized)
{
// log the user in...
}
else
{
ModelState.AddModelError("AuthFail", "Authentication failed, please try again");
return View(login);
}
}
CredentialsAreValid оборачивает вызов BCrypt.CheckPassword:
public bool CredentialsAreValid(string username, string password)
{
var user = GetUser(username);
if (user == null)
return false;
return Password.Compare(password, user.Password);
}
Password.Compare:
public static bool Compare(string password, string hash)
{
return BCrypt.CheckPassword(password, hash);
}
И, наконец, вот что делает BCrypt.CheckPassword:
public static bool CheckPassword(string plaintext, string hashed)
{
return StringComparer.Ordinal.Compare(hashed, HashPassword(plaintext, hashed)) == 0;
}
Итак, да ... Я не знаю, что происходит, но я точно знаю, что моя логическая переменная authorized
в моем действии контроллера входа всегда по какой-то причине возвращает false.
Я использовал этот точно такой же класс BCrypt по крайней мере для пары других проектов в прошлом, и у меня никогда не было проблем с ним вообще. Делает ли ASP.NET MVC 3 какое-то странное, отличное кодирование для публикуемых данных, которые мне не хватает, или мне нужно обрабатывать их по-другому или что-то в этом роде? Либо так, либо SQL CE 4 делает это (это хранилище данных, которое я сейчас использую)? Кажется, что все в порядке в моем коде, что я могу сказать, но по какой-то причине проверка пароля не удается каждый раз. У кого-нибудь есть идеи?
Спасибо.
ОБНОВЛЕНИЕ: Вот комментарии к коду, включенные в класс BCrypt с примерами того, как он используется и работает.
/// <summary>BCrypt implements OpenBSD-style Blowfish password hashing
/// using the scheme described in "A Future-Adaptable Password Scheme"
/// by Niels Provos and David Mazieres.</summary>
/// <remarks>
/// <para>This password hashing system tries to thwart offline
/// password cracking using a computationally-intensive hashing
/// algorithm, based on Bruce Schneier's Blowfish cipher. The work
/// factor of the algorithm is parametized, so it can be increased as
/// computers get faster.</para>
/// <para>To hash a password for the first time, call the
/// <c>HashPassword</c> method with a random salt, like this:</para>
/// <code>
/// string hashed = BCrypt.HashPassword(plainPassword, BCrypt.GenerateSalt());
/// </code>
/// <para>To check whether a plaintext password matches one that has
/// been hashed previously, use the <c>CheckPassword</c> method:</para>
/// <code>
/// if (BCrypt.CheckPassword(candidatePassword, storedHash)) {
/// Console.WriteLine("It matches");
/// } else {
/// Console.WriteLine("It does not match");
/// }
/// </code>
/// <para>The <c>GenerateSalt</c> method takes an optional parameter
/// (logRounds) that determines the computational complexity of the
/// hashing:</para>
/// <code>
/// string strongSalt = BCrypt.GenerateSalt(10);
/// string strongerSalt = BCrypt.GenerateSalt(12);
/// </code>
/// <para>
/// The amount of work increases exponentially (2**log_rounds), so
/// each increment is twice as much work. The default log_rounds is
/// 10, and the valid range is 4 to 31.
/// </para>
/// </remarks>