应使用password_hash()和password_verify()安全处理密码,禁用md5/sha1及手动加盐;默认PASSWORD_DEFAULT自动适配最优算法,数据库字段须设VARCHAR(255)以兼容所有哈希长度。

直接用 password_hash() 存,用 password_verify() 验证,别碰 md5()、sha1() 或手动拼 salt —— 这些不是“不够好”,是已经失效,且极易引入漏洞。
为什么不能用 md5() 或 sha1() 存密码
它们是通用哈希函数,不是为密码设计的:计算太快、不加盐、抗碰撞能力差。一张消费级显卡每秒能跑上亿次 md5() 碰撞,彩虹表库早把常见组合全预计算好了。
- 数据库里看到一堆
5f4dcc3b5aa765d61d8327deb882cf99这类固定长度 32 位字符串 —— 基本就是裸md5() - 登录逻辑里出现
md5($_POST['pass'] . $row['salt']) === $row['password']—— 手动salt管理极易出错,且无法随硬件升级自动增强强度
password_hash() 的参数怎么选才合理
默认调用 PASSWORD_DEFAULT 就够用,它当前指向 bcrypt,未来 PHP 升级可能切到 Argon2,但老哈希仍能被新版本验证。
- 别硬写死
PASSWORD_BCRYPT或PASSWORD_ARGON2ID,除非你明确知道环境限制(比如某些旧容器没装libargon2) -
$options里最常调的是cost:cost => 10到12是合理区间;值每 +1,计算耗时约翻倍 - 设太高(如
16)会导致登录延迟明显,尤其高并发时可能拖垮 Web 服务 - 设太低(如
8)会让暴力破解成本大幅下降,失去 bcrypt 意义 - 不需要传
salt参数 —— 函数内部自动生成并嵌入输出字符串,手动传反而会触发弃用警告
数据库字段必须设成 VARCHAR(255)
password_hash() 输出的字符串长度不固定,当前 bcrypt 最长约 60 字符,Argon2 可达 255 字符。若字段类型是 VARCHAR(32) 或 CHAR(32),插入会截断,导致后续 password_verify() 必然失败。
构建并排查Microsoft Word邮件合并及DOCX模板工作流,使用合并域、内容控件、文档属性、重复区块、数据等
- MySQL 中设为
VARCHAR(255),足够容纳所有当前及可预见的未来算法输出 - 别用
TEXT—— 虽然能存,但索引效率低,且无必要 - 字段名就叫
password_hash,别叫password或pwd,避免语义混淆 - 插入前不用额外过滤或转义 —— 哈希字符串只含 ASCII 可打印字符,不会触发 SQL 注入
password_verify() 验证时最容易忽略的点
它不依赖外部 salt 或算法配置,只靠哈希字符串自身携带的元信息工作,但有几点必须注意:
- 第二个参数必须是完整原始哈希字符串(例如
$2y$10$),不能是截断的、trim()过的、或从 JSON 中decode出来时丢失了末尾空格或换行 - 如果老系统用了
md5(),可在用户下次登录时悄悄升级:先用旧方式验证;验证通过后,立即用password_hash()生成新哈希,更新数据库 - 加个判断避免重复操作:
if (password_needs_rehash($oldHash, PASSWORD_DEFAULT)) { ... }
真正容易被忽略的是哈希字符串的完整性 —— 它看着像普通字符串,但开头几个字符(如 $2y$)决定了算法和 cost,少一个字节,password_verify() 就直接返回 false,且不报错。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










