密码使用相同的用户名散列不同的盐

时间:2014-01-15 11:16:52

标签: c# password-encryption rfc2898

我们在网站上引入了密码加密功能。 盐的计算如下:

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

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

1 个答案:

答案 0 :(得分:1)

假设你也使用RFC2898DeriveBytes来密码密码本身,那么@CodesInChaos是正确的,你做错了是:


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

  • 然后盐应该与密码哈希和迭代计数一起存储在数据库中的clear中(因此你可以更改它),也可能是版本代码(所以你可以再次更改它,即你当前的计算盐方法是版本1,随机盐是版本2)。

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

如果您没有使用RFC2898DeriveBytes,另一个PBKDF2实现,BCrypt或SCrypt来进行实际密码散列,那么 你做错了什么。

修剪用户名,但并非所有时间都是完全包含的;只需确保在密码被散列之前不要修剪密码。