password_hash()是唯一推荐的密码存储函数,因其自动生成盐、抗时序攻击、支持算法升级;而openssl_encrypt等可逆加密因需管理密钥/iv、可解密还原明文、增加攻击面,绝不可用于密码存储。

password_hash() 是唯一推荐用于数据库密码存储的函数,其他任何可逆加密或弱哈希(如 md5()、sha1()、crypt())都不应出现在生产环境的密码字段中。
为什么不能用 openssl_encrypt 加密数据库密码
- 密码不是“需要解密回来”的数据,它的用途只有比对;一旦可逆,就等于把明文风险扩大到密钥泄露、代码审计、内存 dump 等多个环节。
-
openssl_encrypt要求你管理密钥、IV、模式、填充,稍有疏忽(比如重用 IV、硬编码密钥)就会导致整个密码体系崩塌。 - 即使加密成功,登录验证时你还得先解密再比对——这多出的一步不仅没提升安全性,反而引入更多攻击面和错误可能。
-
password_hash()自动生成盐、绑定算法参数、抗时序攻击、支持算法升级(如从 bcrypt 切到 Argon2),而你自己写的加密逻辑做不到这些。
password_hash 和 password_verify 的正确用法
- 存储时直接调用
password_hash($password, PASSWORD_ARGON2ID),返回值是完整字符串(含算法标识、成本因子、盐和哈希),原样存进数据库字段,不要截断、base64 编码或额外拆分。 - 验证时只传入原始密码和数据库里取出来的完整哈希字符串:
password_verify($input, $storedHash),它内部自动提取盐、参数并执行对应算法。 - 不要自己拼接盐,不要用
PASSWORD_BCRYPT以外的常量硬编码算法,更不要尝试“双重哈希”或“加前缀混淆”。
容易被忽略的坑
-
password_hash()返回的字符串长度不固定(Argon2 可达 255 字节),数据库字段必须设为VARCHAR(255)或更长,CHAR(60)是 bcrypt 时代的遗留陷阱。 - 如果从旧系统迁移,旧密码可能是
md5()或sha1()存的,不要批量重哈希,应在用户下次登录时用password_needs_rehash()检查并升级。 - 使用 PDO 或 MySQLi 时,务必用参数化查询插入哈希值,避免把
password_hash()结果拼进 SQL 字符串——虽然哈希本身不含单引号,但养成习惯能防其他字段注入。 -
password_hash()在 PHP 7.2+ 默认启用 Argon2(需 libsodium),若环境不支持,PASSWORD_DEFAULT会退回到 bcrypt;但别手动降级到PASSWORD_BCRYPT,除非明确知道你在放弃现代防护。
真正难的不是写对那两行函数调用,而是说服团队放弃“我加密了所以安全”的错觉,接受“哈希不可逆 + 自动盐 + 算法演进”这套设计哲学。只要密钥、IV、算法选择、错误处理任何一个环节由人手控,它就离真实安全更远一步。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











