ASP.NET标识 - 存储盐的位置在哪里?

w00*_*977 8 c# asp.net

我创建了一个简单的MVC4应用程序并注册了一个用户.usrname和密码存储在名为AspNetUsers的表中.该表没有盐场.

我理解的方式是当用户登录时; 他们输入用户名和密码.然后将盐与输入的密码连接起来,并与数据库中的密码进行比较.这不正确吗?即

Hash(PasswordEntered) + Salt = Password in database = authenticated
Hash(PasswordEntered) + Salt <> Password in database = not authenticated
Run Code Online (Sandbox Code Playgroud)

有一个名为:aspnetusers.SecurityStamp的字段,但我的研究告诉我,这不是Salt.

更新

我刚读过Scott Chamberlain.请参阅以下步骤:

1)用户在注册期间输入:Hello123作为密码,Salt(随机生成)为:456,然后输入PasswordHash的密码为:Hello123 + 456 2)然后用户尝试登录并输入Hello123(正确)作为密码.盐(随机生成)为:567.因此Hello123 + 456与Hello123 + 567进行比较,验证失败.

在这种情况下,用户输入正确的密码并且未经过身份验证.我显然缺少一些基本的东西.

Sco*_*ain 9

您的模式不正确,正确的模式是

Hash(PasswordEntered + Salt)  = hash in database = authenticated
Hash(PasswordEntered + Salt)  <> hash in database = not authenticated
Run Code Online (Sandbox Code Playgroud)

ASP.net提供程序的工作方式是将其存储Salt + Hash(PasswordEntered + Salt)在密码字段中。因此,当您测试密码时,只需在盐中使用分隔符之前的部分,然后将其与分隔符之后的部分进行比较。

在更新中,您出错的部分是用户登录时没有随机生成的盐。它重新使用了用户注册时随机生成的盐,该盐以纯文本格式存储在数据库中,并且没有散​​列。

  • 不,为了使盐有用,每个哈希都应具有唯一的盐。用于盐的值不是秘密信息,不需要隐藏。有关其存储方式的更多详细信息,请参见[此答案](http://stackoverflow.com/a/21496255/80274)。 (2认同)
  • 通常只是存储在另一个数据库字段中或只是附加在哈希前面。盐不是秘密。举例来说,我的盐为 1234,在我的数据库中,我会存储“1234|avsSAFwa41s==”,因此“1234”是盐,“avsSAFwa41s==”是 Base64 编码的密码。当我去验证密码时,我会执行“Hash(1234 + 用户提供的密码)”并检查它是否与“avsSAFwa41s==”匹配 (2认同)

Jac*_* Ng 5

与 asp.net core 3 相同。

Salt + Hash连接并存储到passwordHash数据库中的字段中。

这是如何生成passwordHash 的源代码。

*password参数为明文密码。

*subkey是个hash

https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/PasswordHasher.cs

private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
{
    // Produce a version 3 (see comment above) text hash.
    byte[] salt = new byte[saltSize];
    rng.GetBytes(salt);
    byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

    var outputBytes = new byte[13 + salt.Length + subkey.Length];
    outputBytes[0] = 0x01; // format marker
    WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
    WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
    WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
    Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
    Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
    return outputBytes;
}
Run Code Online (Sandbox Code Playgroud)