PHP的crypt()函数:blowfish salt长度向后兼容性问题

5
我使用crypt()函数以blowfish盐的形式来加密密码,格式如下: $2a$、2个数字、$、21个[a-zA-Z0-9]字符
这里我犯了一个错误,第三个$后面的字符长度是21而不是22。但它仍然可以正常工作,所以我没有发现这个错误。
它可以在我的台式机上运行(Windows和php 5.4.4)以及在AWS ec2上运行(Amazon Linux和php 5.3.x),即使盐太短也可以。
有一天,我升级了AWS的php版本到5.5.14,然后问题就出现了。crypt()函数总是返回*0。
经过尝试,我在盐的末尾添加了一个$,使其变成了22个字符。然后它再次可以工作,并返回与之前相同的哈希字符串。尽管它不符合blowfish规则,字符应该是[./a-zA-Z0-9]。
但现在我将此站点复制到另一台机器上,该机器运行openSuSE 13.1和php 5.5.14,这个盐又失败了。
我将php降级到5.4.20但没有帮助。
新站点仍需要旧数据库,因此我必须让密码哈希值能够正常工作。
是哪个库或模块影响了这个blowfish盐长度错误的兼容性问题?似乎不是PHP的版本。AWS 5.5.14
或者还有其他神奇字符可以再次拯救我吗?我尝试将$替换为[./a-zA-Z0-9]中的每个字符,但没有成功,哈希字符串是不同的...

为什么不使用PHP的哈希函数(http://php.net/manual/en/function.password-hash.php)来生成盐呢? - PeeHaa
现有系统仍需继续工作。 - Jacky Jou
但是现在我在openSuSE 13.1上使用php 5.5.14构建另一个网站,这个salt再次失败了。你完全可以使用适当的工具来完成这项工作,没有任何理由不这样做。 - PeeHaa
这是同一个系统。只需将其复制到另一台使用不同Linux发行版的机器上,使用旧数据库即可。无论如何,这就是我的问题所在。 - Jacky Jou
我编辑了我的问题,使其更加清晰。感谢您的回复。 - Jacky Jou
2个回答

2
首先,我强烈建议您使用新的函数password_hash()password_verify()生成和验证新哈希。当然,这并不能解决旧哈希的实际问题,但标记它们为旧哈希可能是一个好主意,这样它们就可以在下次用户登录时更新。
对于这些旧哈希,我会尝试验证它们,并生成一个有效的最后一个字符为22的盐。crypt函数实际上只使用字符22的一部分比特(128位的盐中的126位)。因此,最后一个字符22的组将以相同的哈希值结束。
请参见此问题的答案Why does crypt/blowfish generate the same hash... 如果您尝试所有相关字符[.Oeu]作为第22个字符,则有很大机会其中一个组合将生成与无效盐相同的结果。
编辑:
由于使用的盐成为密码哈希的一部分,因此您应该能够看到作为第22个字符使用了什么(在第三个$之后的第22个字符)。

@JackyJou - 你怎么知道盐只包含21个字符?crypt函数可能会从“$”中取一些位或填充它。你能给我们展示这样的哈希值吗?一个你知道密码但没有被用户使用的哈希值。 - martinstoeckli
哈希值为'$2a$13$xxxxxB9EUUAe7wKKdye36',并在AWS php 5.3.x和我的Windows 5.4.4上工作。 - Jacky Jou
@JackyJou - 这是完整的哈希值吗?它应该始终具有60个字符的长度。 - martinstoeckli
@JackyJou - 好的,我的意思是当你用结尾的“$”散列化密码时,整个哈希密码看起来像什么,包括所有60个字符。 - martinstoeckli
让我们在聊天中继续这个讨论 - Jacky Jou
显示剩余3条评论

1

如果您降级到PHP 5.4,并再次使用“$”作为最后一个字符,那么您的密码应该可以正常工作(如果)

然而,这不是一种长期解决方案。使用“$”作为最后一个字符会使所有密码无法向前兼容,因为这不是有效的Base64字符(无论是常规还是bcrypt兼容的Base64)。

只要您可以使用PHP 5.4,也就是说只要官方支持PHP 5.4,您就应该在使用旧密码时重新哈希所有旧密码。 在PHP 5.4支持结束后,您将别无选择,只能为仍使用旧哈希方案的用户生成新的随机密码并通过电子邮件发送给他们。

我还建议您使用password-compat package来更新密码。它将为您提供password_*()函数,这些函数否则仅在PHP 5.5+上可用。该包的作者是实现PHP本身函数的同一人,因此您可以确信它既安全又100%兼容,并为您提供向前兼容性,以便升级到5.5+。


在openSuSE 13.1上,使用支持php 5.4或5.5的'$'无法工作,但在AWS ec2上可以使用php 5.5....我很困惑... - Jacky Jou
嗯...好吧,crypt()确实依赖于操作系统的底层API,因此从技术上讲,拥有PHP 5.5甚至不能保证具有Blowfish可用性。虽然我不明白如何在常规的PHP 5.5设置中使用“$”使其工作,但我感到困惑。 - Narf

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