根据 PHP 版本输出两个不同值的 Crypt 函数
Crypt function outputting two different values depending on PHP version
使用密码 "testtest" 和散列 "KFtIFW1vulG5nUH3a0Mv" 以及以下代码会根据 PHP 版本产生不同的散列(如下图所示):
$salt = "KFtIFW1vulG5nUH3a0Mv";
$password = "testtest";
$key = 'a$';
$key = $key.$salt."$";
echo crypt($password, $key);
输出 1(PHP v.5.3.0 - 5.4.41、5.5.21 - 5.5.25、5.6.5 - 5.6.9):a$KFtIFW1vulG5nUH3a0Mv$.0imhrNa/laTsN0Ioj5m357/a8AxxF2q
输出 2(PHP v.5.5.0 - 5.5.20、5.6.0 - 5.6.4):a$KFtIFW1vulG5nUH3a0Mv$e0imhrNa/laTsN0Ioj5m357/a8AxxF2q
这是问题的一个例子:
http://3v4l.org/dikci
如果使用 crypt 来散列登录密码,这将是一个大问题,因为根据 PHP 版本散列会有所不同。任何人都知道这个问题是什么以及如何处理它?
这并没有你想象的那么严重。
首先你应该注意,你的代码不是绝对正确的,BCrypt 需要一个 22 个字符的盐,但你提供了一个 20 个字符的盐。这意味着终止“$”(顺便说一句,这不是必需的)将被视为盐的一部分,以及密码的第一个字母。 $
不是 BCrypt salt 的有效字符。
另外一个要考虑的是,并不是字符22的所有位都被使用,这是由于编码的原因,ircmaxell给了一个good explanation about this. So different salts can result in the same hash, you can see this well in this answer。理论上,不同的实现如何处理字符 22 的最后一位可能会发生变化。只要 crypt 函数可以用两个哈希值验证密码就没有问题。
salt 的生成及其缺陷是原因之一,为什么函数 password_hash() and password_verify() 写在哪里,它们使密码处理更容易。
使用密码 "testtest" 和散列 "KFtIFW1vulG5nUH3a0Mv" 以及以下代码会根据 PHP 版本产生不同的散列(如下图所示):
$salt = "KFtIFW1vulG5nUH3a0Mv";
$password = "testtest";
$key = 'a$';
$key = $key.$salt."$";
echo crypt($password, $key);
输出 1(PHP v.5.3.0 - 5.4.41、5.5.21 - 5.5.25、5.6.5 - 5.6.9):a$KFtIFW1vulG5nUH3a0Mv$.0imhrNa/laTsN0Ioj5m357/a8AxxF2q
输出 2(PHP v.5.5.0 - 5.5.20、5.6.0 - 5.6.4):a$KFtIFW1vulG5nUH3a0Mv$e0imhrNa/laTsN0Ioj5m357/a8AxxF2q
这是问题的一个例子: http://3v4l.org/dikci
如果使用 crypt 来散列登录密码,这将是一个大问题,因为根据 PHP 版本散列会有所不同。任何人都知道这个问题是什么以及如何处理它?
这并没有你想象的那么严重。
首先你应该注意,你的代码不是绝对正确的,BCrypt 需要一个 22 个字符的盐,但你提供了一个 20 个字符的盐。这意味着终止“$”(顺便说一句,这不是必需的)将被视为盐的一部分,以及密码的第一个字母。 $
不是 BCrypt salt 的有效字符。
另外一个要考虑的是,并不是字符22的所有位都被使用,这是由于编码的原因,ircmaxell给了一个good explanation about this. So different salts can result in the same hash, you can see this well in this answer。理论上,不同的实现如何处理字符 22 的最后一位可能会发生变化。只要 crypt 函数可以用两个哈希值验证密码就没有问题。
salt 的生成及其缺陷是原因之一,为什么函数 password_hash() and password_verify() 写在哪里,它们使密码处理更容易。