PHP7中password_hash()空字节漏洞是否存在及密码处理注意事项问询
嘿,针对你关于password_hash()的几个疑问,我来逐一解答:
PHP7中password_hash()的空字节漏洞是否仍存在?
答案是不存在了。这个空字节截断漏洞是早期PHP版本(主要是PHP5.x)的问题:当时password_hash()底层依赖的crypt()函数遇到空字节\0时会截断字符串,只哈希\0之前的部分。比如password_hash("pass\0secret", PASSWORD_DEFAULT)实际只哈希了"pass",这就导致攻击者可以用"pass"来验证通过原本需要"pass\0secret"的哈希。
但从PHP7开始,官方已经修复了这个问题——password_hash()现在会完整处理包含空字节的字符串,把\0和后面的所有字符都纳入哈希计算。这也是你复现失败的原因:现在password_verify()必须匹配完整的原始字符串(包括空字节和后续内容)才会返回true,如果\0后的字符不同或者缺失,验证自然失败。
举个PHP7+下的实际测试例子:
$hash = password_hash("myPass\0extraChars", PASSWORD_DEFAULT); // 验证不完整的字符串,返回false var_dump(password_verify("myPass", $hash)); // 验证完整字符串,返回true var_dump(password_verify("myPass\0extraChars", $hash));
处理密码时的其他注意事项
既然你不想修改用户输入的密码(这非常正确!),除了空字节的问题,还有这些关键事项要注意:
- 绝对不要篡改用户输入的密码字符串:不管是转义特殊字符、截断过长内容,还是过滤所谓的“非法字符”,任何修改都会导致用户实际输入的密码与存储的哈希不匹配,直接影响登录。原封不动传递给
password_hash()是最优选择。 - 优先使用
PASSWORD_DEFAULT作为算法参数:这个常量会自动适配PHP官方推荐的最安全哈希算法(当前是bcrypt,未来可能随PHP版本升级到更安全的算法),避免手动指定过时或不安全的算法。 - 合理设置密码长度限制(可选):
password_hash()支持任意长度的密码,但如果业务需要限制,建议设置一个宽松的上限(比如255字符)——过长的密码不会提升安全性,反而可能占用不必要的服务器资源。 - 永远不要存储明文密码:哪怕是测试环境、日志文件,都必须只存储
password_hash()生成的哈希值,绝对不能保留明文密码的任何副本。 - 不要自行实现哈希或加盐逻辑:
password_hash()已经自动处理了随机加盐、算法迭代次数等安全细节,手动实现很容易引入安全漏洞。 - 定期更新哈希(可选):当PHP更新了默认哈希算法,或者你想提高哈希的成本因子时,可以在用户登录时检查现有哈希是否符合新标准,若不符合,验证通过后用新规则重新哈希并更新数据库中的值。
内容的提问来源于stack exchange,提问作者Dwarf Vader
相关产品推荐
相关产品推荐

