我总是听说最好在存储的密码之上使用盐,然后以某种方式将其连接起来并在之后进行哈希处理。但我不知道用什么做盐。什么是好盐?
什么应该用作盐?
用于密码散列的盐的经典建议是:
- 128位或更多的随机值;
- 从加密健全的随机数生成器(
/dev/random
或/dev/urandom
现代 Unix 上)获得; - 每个条目都是唯一的(即不要重复使用相同的盐,为每个新密码生成一个新的盐);
- 以明文形式存储在数据库中(以便在验证哈希时可以使用盐)。
过去有很多相关主题的讨论。最重要的是,您不应该实现自己的密码哈希方案——您应该使用经过验证、经过良好测试、同行评审的实现 (bcrypt/PBKDF2)。
假设您有一个表,您将在其中存储每个人的密码。
要“保存”正在生成的密码,请执行以下操作
- 从用户那里获取登录信息
- 获取密码
- 从随机值生成一些盐。假设,从 /dev/random (正如@Michal 建议的那样),你得到了“a12bc34de56fg”
- 使用一些散列函数来生成散列密码。假设原始密码是“1password”,您将使用任何 SHA 散列。你会做
hashed_password = SHA(SHA(SHA(.... SHA("1passworda12bc34de56fg"))))))))
将该 hashed_password 与登录名和 salt 一起存储在表中。
login password salt
--------------------------------------
john a7b82783... a12bc34de56fg
然后,验证用户何时访问您的应用程序:
- 获取登录名和密码
- 从数据库中检索该登录的盐(您将拥有盐:a12bc34de56fg)
- 将纯文本密码与盐连接起来,然后再次进行所有散列:
hashed_password = SHA(SHA(SHA(.... SHA("1passworda12bc34de56fg"))))))))
验证您计算的 hashed_password 是否与存储在数据库中的相同。你会知道密码是否正确。
而已!。你可以从任何你喜欢的随机来源获得盐。为什么它应该是随机的?因为任何非随机盐都会使尝试暴力破解您的应用程序变得更加容易。
答案是“几乎任何东西”,尽管有些人比其他人更强大。
假设您使用的是 md5(salt.password)。
没有盐,黑客只需在彩虹表中查找哈希值,就可以快速破解大部分密码。
假设您使用“x”作为所有密码的盐。您的许多密码仍会被发现,但会更少。那是因为如果密码是“p4ssw0rd”,那么它会变成“xp4ssw0rd”,加了盐——稍微难一点,但不是很明显。
现在假设您使用“%X88Fc+7”作为所有密码的一种盐。在这一点上,彩虹表不起作用。但是,对所有密码使用一种盐的结果是,黑客将能够根据该假设生成彩虹表,并提前构建彩虹表。它更安全,但并不完美。
下一个最安全的选项是使用用户名作为盐,换句话说,使用“md5(username.password)”。同样,这破坏了标准彩虹表,但黑客可能会为特定用户名(如“root”或“管理员”)生成彩虹表,因此每次更改密码时,黑客都可以查看彩虹表表而不是再次破解它。
因此,为了更加安全,请为不同的用户选择不同的随机盐。您必须将其与用户名和密码哈希一起存储。这完全击败了彩虹表。
有些人建议使用“安全”随机数生成器,而不是简单的东西。例如,在用户创建帐户时执行 MD5(时间戳+用户名)很简单,但在密码学上并不安全(因为时间戳和用户名是可预测的,因此熵很低)。但是,由于黑客在窃取数据库时无论如何都有盐的副本,所以这不是问题。
对于盐,只需使用随机位。
在 Linux 上,您可以使用/dev/urandom
. 它是一种基于环境噪声的随机数生成器。除了虚拟机之外,这是非常不可预测的。因此,如果您假设将物理鼠标插入您的盒子,那么/dev/urandom
将为您提供高质量的随机位并且对盐有好处。
这是一篇很好的文章。另请参阅外部参考。
这是一个示例 java 代码。在函数中查看盐是如何生成和存储在 DB 中的createUser()
。除了使用import sun.misc. ...
它是非常好的代码。