4

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

これは 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 クラスに含まれるコード コメントと、その使用方法と動作の例を次に示します。

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

3 に答える 3

1

何かが足りない場合はご容赦ください。ただし、ハッシュとモデルを見ると、ソルトはどこにも保存されていないようです。代わりに、毎回新しいソルトを使用します。

したがって、パスワードを設定するときは、ハッシュとソルトの両方を保存する必要があります。入力したパスワードを確認したい場合は、ソルトを取得し、それを使用してハッシュを計算し、保存されているパスワードと比較します。

于 2011-06-03T02:21:17.213 に答える
1

私も同じ問題を抱えていました。BCryptHelper.CheckPassword は常に false を返します

ハッシュされた文字列が nchar() としてデータベースに格納されていることがわかりました。これにより、チェックが常に失敗していました。これを char() に変更したところ、機能しました。

于 2014-04-03T11:34:11.427 に答える
0

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-07-02T04:22:36.427 に答える