安全密码哈希化

18
我需要在一个.Net WinForms应用程序中存储单个密码的哈希值。
最安全的方法是什么?
特别地:
- 确定是否需要盐(Salt)、HMAC或两者兼备? - 盐的量是多少? - 需要进行多少次迭代? - 采用何种编码方式?(密码为纯ASCII)
我假设算法应该是SHA512或HMACSHA512。

无法建议最安全的方式(尽管这是一个关于你想要达到多高程度的问题),但请确保它绝对是单向哈希,并且足够安全,即使你非常努力地尝试,也无法获取密码。例如,如果有大客户抱怨或要求获取密码。 - tjmoore
我认为SHA512是一种安全哈希。 - SLaks
1
我认为“最安全”的问题并不是真正合适的问题。这是一个基于被保护数据的重要性,找到安全、复杂性和用户便利之间平衡的问题。我们是在谈论保护银行账号还是视频游戏分数?可能的攻击者是脚本小子还是国家安全局? - Tim Sylvester
2
@Tim:用户方便性不是一个因素。我会有一个密码;我只是在询问最好的哈希方式。 - SLaks
请阅读:https://dev59.com/onRA5IYBdhLWcg3w2x2W#817121 - Sam Saffron
9个回答

32

为避免彩虹攻击,请使用至少128位或更长的安全随机盐来给您的哈希加盐,并使用 BCrypt, PBKDF2, 或 scrypt。 PBKDF2已获得NIST批准

引用一下:Archive.org: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html

问题在于MD5速度很快。与SHA1和SHA256等现代竞争对手一样。速度是现代安全哈希的设计目标,因为哈希是几乎每个加密系统的构建块,并且通常在每个数据包或消息基础上按需执行。

密码哈希函数中不应该具备速度优势。

快速的密码验证函数会导致问题,因为它们可以遭受暴力破解攻击。使用以上所有算法,您都可以控制“缓慢性”。


速度是消息摘要函数非常重要的部分。NIST在其淘汰过程中排除了慢速消息摘要,以选择下一个标准。 - rook
9
有时我想知道人们是否在给我的答案点踩之前先阅读了它们。 - Sam Saffron
3
我想补充说,有一个本地的.Net实现PBKDF2的工具叫做Rfc2898DeriveBytes,目前来看这可能是最好的选择。 - Keith

8

我可以推荐 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);

5

对于具有大量密码的服务器端实现,您应该绝对使用可调节的迭代方法,如bcrypt。这篇关于该主题的知名文章仍然(大部分)相关:

http://www.securityfocus.com/blogs/262

对于独立应用中的单个密码,存储位置很可能已经由系统自身的认证系统保护,我认为这不是很重要。一个强大的哈希值可能已经足够了,添加盐非常容易,没有理由不这样做。


2
使用 RNGCryptoServiceProvider 生成随机盐,然后使用盐对密码进行 SHA512 加密,最后存储密码哈希和相应的盐,以便稍后验证某些文本是否等于存储的密码。请注意保留 HTML 标签。

你认为我不应该使用HMAC,还是使用迭代哈希? - SLaks
2
在我看来,使用随机盐的SHA-512已经足够强大了。这里有一篇不错的文章http://www.aspheute.com/english/20040105.asp,只需使用SHA-512代替SHA-1即可。 - Darin Dimitrov
HMAC引入了你不需要的问题(密钥)。 - Noon Silk
4
bcrypt是一个明显更好的方法。 - Sam Saffron
3
SHA512不是一个好的选择:它速度过快。bcrypt更好。 - D.W.

1

散列和盐。如果只是散列,可能会受到彩虹攻击(逆向散列查找)的威胁,而添加盐可以增加难度(最好使用随机盐)。对于编码,你可能想要使用Base64或十六进制对生成的字节数组进行编码。如果只是尝试将字节数组存储为Unicode,可能会有数据丢失的风险,因为并非所有模式都是有效字符。这还可以更容易地比较散列值(在验证时只需比较base64或十六进制字符串,而不是比较字节数组)。

增加循环次数除了能够减慢潜在攻击者的速度外,并没有太多作用。但是,如果你丢失或需要重新创建散列算法,增加循环次数也会使未来重用散列变得更加困难。你可以参考像unix系统上的标准密码散列crypt,它允许你更换散列算法,甚至支持版本控制。

但总的来说,在大多数应用程序中,一个简单的散列加盐已经足够了。


1

严格考虑更安全的方法:

盐、HMAC,还是两者皆有?

两者都更加安全。由于 HMAC 的密钥可以被视为一种盐,进行两者操作有点冗余,但仍更加安全,因为破解所需的工作量会更大。

需要多少盐?

每个盐位将使需要在彩虹表中维护的组合数量翻倍,以轻松破解密码。但是由于只有一个密码和一个盐,可能不需要更多。HMAC 使用底层哈希的块大小作为其密钥大小,例如 SHA512 的块大小为 1024 位。该块大小对于盐应该足够好,但加倍或加三倍可以使使用彩虹表破解密码变得更加困难。

需要多少迭代次数?

越多越好。当然,更多的迭代意味着确定正确密码所需的时间更长,但计算机速度很快,用户不介意等待几秒钟来验证密码。进行更多的迭代意味着破解密码的人也必须执行更多的迭代。

采用哪种编码?(密码为纯 ASCII)

最好使用AES加密超级安全的密码,包括其盐,以使其更难破解。将加密密码哈希和密钥的密码设置为一些字符串组合,这些字符串应该出现在可执行文件中,例如“RNGCryptoServiceProvider”或“System.Security.Cryptography”。在编码时,最好将其转换为十六进制、Base64,或者更好的是Base-36或其他不太常见的转换方式。

注意:这主要是开玩笑写的,但仍应包含一些真实性。


1

我认为您应该坚持使用开放标准。在当前的哈希方案中,OpenLDAP 使用的 "{ssha}" 非常安全且被广泛使用。您可以在这里找到相关描述。

http://www.openldap.org/faq/data/cache/347.html

大多数LDAP库都实现了这个方案。


1

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接