【问题标题】:ASP.NET MVC 3 app, BCrypt.CheckPassword failingASP.NET MVC 3 应用程序,BCrypt.CheckPassword 失败
【发布时间】:2011-06-03 01:59:50
【问题描述】:

我正在致力于在 ASP.NET MVC 3 应用程序中实现安全性,并且正在使用 BCrypt 实现 found here 来处理密码的加密和验证。用户注册屏幕对用户提供的密码进行了很好的加密,散列后的密码被保存到数据库中。我在登录页面上的密码验证出现问题,我似乎无法弄清楚原因。

我的注册控制器操作包含以下内容:

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

这是 Password.Hash:

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

密码.比较:

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 类中包含的代码 cmets,以及它的使用和工作示例。

/// <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>

【问题讨论】:

  • 有人找到答案了吗?我似乎遇到了同样的问题。
  • 不,我什么都没得到。我最终不得不改用 SHA512 并存储盐。抱歉,我无法提供更多帮助。

标签: asp.net-mvc bcrypt sql-server-ce-4


【解决方案1】:

如果我遗漏了什么,请原谅我,但是看看你的哈希和你的模型,你似乎没有将盐存储在任何地方,而是每次都使用新的盐。

所以当设置密码时,你必须同时存储哈希值和盐值;当您想检查输入的密码时,您检索盐,使用它计算哈希值,然后与存储的密码进行比较。

【讨论】:

  • 根据 BCrypt 类中的代码文档/cmets,它不是这样工作的。它的工作方式与 .NET 框架中的标准 SHA1 散列算法的工作方式不同。我将使用随附的代码文档编辑上面的原始帖子。
  • 啊,我明白了,盐以明文形式存储在哈希中。
【解决方案2】:

我遇到了同样的问题。 BCryptHelper.CheckPassword always returns false

我发现哈希字符串作为 nchar() 存储在数据库中。这导致检查总是失败。 我将其更改为 char() 并且可以正常工作。

【讨论】:

    【解决方案3】:

    HttpUtility.HtmlDecode() 在创建用户时使用,在密码最初散列之前:

    Password = Password.Hash(HttpUtility.HtmlDecode(registration.Password)),
    

    然而,HttpUtility.HtmlDecode() 稍后在比较密码和哈希时不使用,在

    var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), login.password);
    

    也许稍微改变一下:

    var authorized = _repository.CredentialsAreValid(HttpUtility.HtmlDecode(login.username), HttpUtility.HtmlDecode(login.password));
    

    我意识到这是一个较老的问题,但我正在考虑使用 BCrypt,这个问题对我来说是一个潜在的问题,所以我很想知道这是否能解决这个问题。抱歉,我目前无法验证我的答案,但希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      相关资源
      最近更新 更多