重新散列哈希 (SHA512)

Rehashing a hash (SHA512)

我们正在执行非常标准的用户 ID/密码检查。我们将哈希密码存储在数据库中。当用户输入凭据时,我们对输入的密码进行哈希处理,然后与数据库中的密码进行比较。如果它们匹配,则用户通过身份验证。

现在这个负载测试下的登录过程明显变慢,所以我被要求查看它。 VS 2013 Profiler 将哈希方法指出为热路径。查看有问题的方法,我们正在遍历哈希过程??

private const int totalHashCount = 1723;

public string CreateHash(string salt, string password, int securityIndex)
{
  string hashedPass = this.GenerateHashString(salt + password, securityIndex);
  for (int i = 1; i <= totalHashCount; i++)
  {
    hashedPass = this.GenerateHashString(hashedPass, securityIndex);
  }
  return hashedPass;
}

我去找了开发人员,他说客户的安全团队希望我们重新散列哈希并使用大于 1000 的素数....他提供了电子邮件作为文档。

现在我不是密码学专家,我们与客户的关系很好,所以在我去找他们并将这个重新散列循环与他们的性能问题联系起来之前,我想看看这样的重新散列是否确实提高了安全性?

根据我的理解,单个散列实际上是不可能反转的,所以为什么要浪费循环重复这个过程?

想法?


编辑

添加了生成哈希:

protected internal string GenerateHashString(string textToHash, int securityIndex = 0)
{
   UnicodeEncoding uEncode = new UnicodeEncoding();
   SHA512Managed sha = new SHA512Managed();

   byte[] bytVal = uEncode.GetBytes(textToHash + hashIntPool[securityIndex].ToString());
   byte[] hashVal = sha.ComputeHash(bytVal);

   return Convert.ToBase64String(hashVal);
 }

称为 "stretching" 的重复散列技术用于使暴力攻击更加困难。如果哈希密码需要 0.1 秒(由于重复),那么攻击者最多可以每秒尝试 10 个密码来找到匹配项。如果您加快散列过程以使其花费一微秒,那么攻击者每秒可以测试一百万个密码。

您需要在速度与安全之间取得平衡。用户登录只要快到用户满意即可,0.1到0.5秒大概可以接受。

如果您的服务器过载,请获得更快的处理器,或购买专用的哈希服务器。这比数据泄露的法律后果要便宜得多。

重复哈希操作对于安全密码验证至关重要,但你做错了,因此确实浪费了 CPU 一无所获。

您应该使用像 PBKDF2 这样的算法,在每一轮哈希中都包含密码,以保留密码的所有不可预测性。 bcrypt 尤其是 scrypt 也是不错的选择。

还有,一千发远远不够;为了抵御离线字典攻击,您需要散列操作相对较慢,即使在攻击者的专用密码测试硬件上执行时也是如此。选择一个质数的回合是毫无意义的胡言乱语。轮数将取决于您使用的算法 select,但对于使用 SHA-256 的 PBKDF2,10,000 到 100,000 轮之间的某个位置应该提供合理的安全级别。

需要一种缓慢的算法来防止获得散列的攻击者快速尝试许多不同的密码以查看哪个产生相同的散列。确实,安全散列无法反转,但它不会停止猜测,并且攻击者擅长确定他们猜测的优先级,首先尝试最有可能的密码。哈希的重复是提供这种必要的缓慢的原因。

这已在 Whosebug 上讨论过多次。我建议您参考 a previous answer 了解更多背景信息。

在 C# 中,您可以使用 Rfc2898DeriveBytes to perform password hashing securely. You can encode the derived key in Base-64 to be stored as a string, or actually use it as an encryption key to encrypt a known plain text like the bcrypt algorithm does. You'll notice that Rfc2898DeriveBytes uses a "salt", which I discuss elsewhere;您需要将此值与哈希值一起存储以便稍后执行身份验证。