我目前正在实施一个利用PHP的new(将作为v5.5的一部分发布)密码处理API的webapp。我认为它真的很好,但我想知道是否有人知道为什么password_get_info()
不返回给定哈希计算中使用的salt值? RFC明确指出有问题的函数不返回salt,但没有解释为什么:
第二个元素是“选项”,其中包括使用的选项 散列算法,但使用的盐除外。
我问的原因是因为当用户的密码到期时,我需要检查他们是否重新提交与当前密码相同的密码。执行此操作的唯一方法是对新密码进行哈希处理,使用相同的算法,成本和盐将生成的哈希值与当前数据库中的哈希值进行比较。算法和费用由password_get_info()
函数返回,但不归盐。目前,我使用substr($hash, 7, 22)
来获取盐值,但这显然是算法特定的,有点挫败了使用其他非常容易使用且功能强大的API的目的(如果我开始使用新算法的位置盐很可能会改变。)
password_verify()
并检查它是否返回FALSE
。这会教我在生病和疲倦的情况下工作!
答案 0 :(得分:2)
相反,您无需了解此信息。只需将输入与之前的哈希进行比较(通过这个,我的意思是存储用户拥有的每个哈希的记录并遍历所有哈希,检查password_verify
对新密码输入的结果。)
Bcrypt很有用;实际上,这是password_hash
或password_verify
将使用的任何算法的必需行为,因为否则您无法以相同的方式进行比较,并且功能会发生变化。
password_verify(string $password, string $hash):
$hash = crypt($plaintext, '$2y$' . $workrate . '$' . $salt)
=> $2y$<workrate>$<salt><hash> as result,
但是,如果你真的需要找到bcrypt哈希的盐(这是password_hash
使用的),那么只需取哈希的前22个字符,减去设置(但我会重复,但是,你只需要将输入与哈希进行比较)。
理想情况下,您应该将password_hash
包装在可以处理动态工作量和更改选项的类或函数中(例如,如果将哈希值保存为工作率12,则可以使用不同的工作率基于哈希的年龄,并鼓励用户更新他们的密码。)
函数不返回salt,因为它是由CSPRNG生成的,根本不需要作为单独的参数进行比较(因为它是散列的一部分)
答案 1 :(得分:0)
这是一个老问题,但我认为我的回答高于目前接受的范围。
那么password_get_info()
为什么不给你一个盐?这是因为您的salt已经存储在哈希中。因此,当你向password_verify
提供hast时,它可以提取盐。
自己检查一下:
password_hash('password', PASSWORD_DEFAULT, [
'salt' => 'mySaltShouldBeVeryLong
]);
结果如下:"$2y$10$mySaltShouldBeVeryLonevYKGp78vooNv9Y7Kwy29CBdNLSUOutS"
。如果您仔细观察,您会注意到与盐的相似性。但提供自己的盐并不是一个好主意(很难让它变得独一无二)。因此,算法将负责生成自己的盐。因此,您可以看到
password_hash('password', PASSWORD_DEFAULT) !==
password_hash('password', PASSWORD_DEFAULT)
哈希是完全不同的,因为使用了不同的盐。这样做是因为普通开发人员的安全性不强,不知道盐,胡椒,碰撞和其他很酷的词汇是什么。
使用password_hash()创建哈希值,使用password_verify()检查是否正确。看一下password_hash()中的成本参数。