最安全的方法是什么?
特别地:
- 确定是否需要盐(Salt)、HMAC或两者兼备? - 盐的量是多少? - 需要进行多少次迭代? - 采用何种编码方式?(密码为纯ASCII)
我假设算法应该是SHA512或HMACSHA512。
Rfc2898DeriveBytes
,目前来看这可能是最好的选择。 - Keith我可以推荐 BCrypt.net。非常易于使用,而且您可以调整哈希所需的时间长度,这很棒!
// Pass a logRounds parameter to GenerateSalt to explicitly specify the
// amount of resources required to check the password. The work factor
// increases exponentially, so each increment is twice as much work. If
// omitted, a default of 10 is used.
string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12));
// Check the password.
bool matches = BCrypt.CheckPassword(candidate, hashed);
对于具有大量密码的服务器端实现,您应该绝对使用可调节的迭代方法,如bcrypt。这篇关于该主题的知名文章仍然(大部分)相关:
http://www.securityfocus.com/blogs/262
对于独立应用中的单个密码,存储位置很可能已经由系统自身的认证系统保护,我认为这不是很重要。一个强大的哈希值可能已经足够了,添加盐非常容易,没有理由不这样做。
散列和盐。如果只是散列,可能会受到彩虹攻击(逆向散列查找)的威胁,而添加盐可以增加难度(最好使用随机盐)。对于编码,你可能想要使用Base64或十六进制对生成的字节数组进行编码。如果只是尝试将字节数组存储为Unicode,可能会有数据丢失的风险,因为并非所有模式都是有效字符。这还可以更容易地比较散列值(在验证时只需比较base64或十六进制字符串,而不是比较字节数组)。
增加循环次数除了能够减慢潜在攻击者的速度外,并没有太多作用。但是,如果你丢失或需要重新创建散列算法,增加循环次数也会使未来重用散列变得更加困难。你可以参考像unix系统上的标准密码散列crypt,它允许你更换散列算法,甚至支持版本控制。
但总的来说,在大多数应用程序中,一个简单的散列加盐已经足够了。
严格考虑更安全的方法:
盐、HMAC,还是两者皆有?
两者都更加安全。由于 HMAC 的密钥可以被视为一种盐,进行两者操作有点冗余,但仍更加安全,因为破解所需的工作量会更大。
需要多少盐?
每个盐位将使需要在彩虹表中维护的组合数量翻倍,以轻松破解密码。但是由于只有一个密码和一个盐,可能不需要更多。HMAC 使用底层哈希的块大小作为其密钥大小,例如 SHA512 的块大小为 1024 位。该块大小对于盐应该足够好,但加倍或加三倍可以使使用彩虹表破解密码变得更加困难。
需要多少迭代次数?
越多越好。当然,更多的迭代意味着确定正确密码所需的时间更长,但计算机速度很快,用户不介意等待几秒钟来验证密码。进行更多的迭代意味着破解密码的人也必须执行更多的迭代。
采用哪种编码?(密码为纯 ASCII)
最好使用AES加密超级安全的密码,包括其盐,以使其更难破解。将加密密码哈希和密钥的密码设置为一些字符串组合,这些字符串应该出现在可执行文件中,例如“RNGCryptoServiceProvider”或“System.Security.Cryptography”。在编码时,最好将其转换为十六进制、Base64,或者更好的是Base-36或其他不太常见的转换方式。
注意:这主要是开玩笑写的,但仍应包含一些真实性。
我认为您应该坚持使用开放标准。在当前的哈希方案中,OpenLDAP 使用的 "{ssha}" 非常安全且被广泛使用。您可以在这里找到相关描述。
http://www.openldap.org/faq/data/cache/347.html
大多数LDAP库都实现了这个方案。