【问题标题】:Hash on Unicode Password对 Unicode 密码进行哈希处理
【发布时间】:2010-11-16 15:52:04
【问题描述】:

我正在为我的 .NET 应用程序编写密码盐/哈希程序,主要遵循本文的指南: http://www.aspheute.com/english/20040105.asp

计算加盐哈希的代码基本上是这样的:

public string ComputeSaltedHash(string password, byte[] salt) {

    // Get password ASCII text as bytes:
    byte[] passwordBytes = System.Text.Encoding.ASCII.GetBytes(password);

    // Append the two arrays
    byte[] toHash = new byte[passwordBytes.Length + salt.Length];
    Array.Copy(passwordBytes, 0, toHash, 0, passwordBytes.Length);
    Array.Copy(salt, 0, toHash, passwordBytes.Length, salt.Length);

    byte[] computedHash = SHA1.Create().ComputeHash(toHash);

    // Return as an ASCII string
    return System.Text.Encoding.ASCII.GetString(computedHash);
}

但是,我想允许用户在他们的密码中使用 Unicode 字符,如果他们愿意的话。 (这似乎是个好主意;谁能想到它不是的原因?)

但是,我不太了解 Unicode 的工作原理,而且我担心如果我只是将 System.Text.Encoding.ASCII 的两个引用更改为 System.Text.Encoding.Unicode,哈希算法可能会产生一些不形成的字节组合有效的 Unicode 字符和 GetString 调用会崩溃。

这是一个合理的担忧,还是可以?

【问题讨论】:

    标签: .net unicode hash passwords


    【解决方案1】:

    您不应该使用 any 普通编码将任意二进制数据转换回字符串。它不是编码文本——它只是一个字节序列。不要试图将其解释为“正常”文本。原始密码是否包含任何非 ASCII 字符与此无关 - 您当前的密码已损坏。 (在此基础上,我会对链接的文章抱有很大的怀疑。)

    我建议:

    • 使用Encoding.UTF8 从密码中获取字节。这将允许密码包含任何 Unicode 字符。 Encoding.Unicode 在这里也可以。
    • 使用Convert.ToBase64String 将计算的哈希值转换回文本。 Base64 专门用于在 ASCII 字符集中以文本形式表示不透明的二进制数据。

    【讨论】:

    • 好点。这个问题不仅仅与 Unicode 实现有关。现有的 ASCII 实现同样存在缺陷。
    • 感谢您对 ASCII 编码的这一有见地的评论。这让我想起了 Eric Lippert 的一篇帖子,其中的寓意是“不要使用你不完全理解的密码系统”(blogs.msdn.com/b/ericlippert/archive/2009/12/14/…)。附: - 刚刚收到我的 C# in Depth 2ed 电子书,期待花一些时间阅读它!
    【解决方案2】:

    将第一个引用更改为UnicodeUTF-8 就足够了。但是,您可能希望对输入进行规范化,以考虑输入重音等各种方式。

    【讨论】:

      【解决方案3】:

      我更喜欢 Jon 解决方案,但另一种选择是将原始十六进制简单地存储为字符串。将最后一行替换为:

      return BitConverter.ToString(computedHash)
      

      您可能需要考虑的一件事是密码强化。
      SHA1 非常快,有时也太快了。一个系统将能够每秒计算几百万个哈希值。该速度允许攻击者尝试常见的字典攻击(包括大小写变体)和数字扩展。 SHA1 的速度允许在合理的时间内完成广泛的字典空间,从而破解大多数用户的密码。

      加强密码的一种方法是对其进行多次散列,这会增加散列的 CPU 要求。获取 SHA1 哈希的输出并将其作为输入传递给第二轮。这样做至少 1000 次。这会减慢您和攻击者的哈希计算速度。对于您的用户来说,它会延迟访问一小段时间;例程将在 0.01 秒而不是 0.0001 秒内返回。但是对于蛮力攻击,您将执行时间增加了 1000 倍。

      您可以自己滚动,但 .net 框架公开了一个类来做到这一点: System.Security.Cryptography.Rfc2898DeriveBytes

      RFC2898 使用 SHA1 算法并接受纯文本、盐和迭代次数。它可以输出可变长度的密钥。

      http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-06
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多