0

我们为我们的网站引入了密码加密。盐的计算如下所示:

Rfc2898DeriveBytes hasher = new Rfc2898DeriveBytes(Username.ToLowerInvariant(),
           System.Text.Encoding.Default.GetBytes("Wn.,G38uI{~6y8G-FA4);UD~7u75%6"), 10000);
string salt = Convert.ToBase64String(hasher.GetBytes(25));

对于大多数用户名,盐总是相同的。但是对于某些用户名,它在每次通话时都会改变。有人能告诉我我们做错了什么吗?

4

1 回答 1

1

假设您也使用 RFC2898DeriveBytes 对密码本身进行哈希处理,那么 @CodesInChaos 是正确的,您做错的是:


byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
  {
  // Fill the array with a random value.
  rngCsp.GetBytes(salt1);
  }

  • 然后盐应该与密码哈希和迭代计数一起以明文形式存储在数据库中(以便您可以更改它),并且可能还有一个版本代码(因此您可以再次更改它,即您当前计算的盐方法是版本 1 , 随机盐是版本 2)。

    • 在盐上花费 20,000 次 PBKDF2 迭代,而不是在实际密码哈希上花费!
  • 前 20 个字节进行 10,000 次迭代,因为 RFC2898DeriveBytes 是 PBKDF2-HMAC-SHA-1,而 SHA-1 具有原生 20 字节输出
  • 接下来的 20 个字节再进行 10,000 次迭代,然后将其截断为仅需要 5 次才能获得 25 字节的输出。
  • 这是一个弱点,因为防御者必须在每次登录时都花时间在盐上,无论是花在盐上还是密码散列上。攻击者必须为每个用户名花费一次时间,然后他们将存储结果并尝试_illions(其中 _非常大)的密码猜测。
    • 因此,攻击者具有比正常情况更大的边际优势,因为他们可以预先计算盐,而您必须即时计算它。

如果您没有使用 RFC2898DeriveBytes、另一个 PBKDF2 实现、BCrypt 或 SCrypt 来执行实际的密码散列,那么就是您做错的事情。

对用户名进行一些调整,但并非总是如此,这完全是偶然的;只要确保在散列之前不要修剪密码。

于 2014-04-08T04:40:17.813 回答