md5不能当加密函数用,因为它是单向哈希,不接受密钥、不可逆,无法还原原始密码;且已被碰撞攻击破解,无盐时相同密码生成相同哈希,易受彩虹表攻击。

MD5 和 SHA2 都不能“加密”密码,只能做哈希;真要安全,必须加盐、用 SHA2(, 256),且永远别用 MD5。
为什么不能把 MD5() 当成加密函数用?
MD5 是单向哈希,不是加密——它不接受密钥,也不可逆。你执行 SELECT MD5('123') 得到 '202cb962ac59075b964b07152d234b70',但没有任何 MySQL 函数能把这个结果还原成 '123'。有人误以为这是“加密”,结果上线后才发现:连自己都查不出原始密码,重置逻辑全崩。
- MD5 已被公开碰撞攻击,2026 年还在生产环境用它存密码,等于裸奔
-
MD5()输出固定 32 字符十六进制,字段至少定义为VARCHAR(32),否则截断 - 它不抗彩虹表:相同密码 → 相同哈希 → 一破全破
SHA2(str, 256) 怎么用才不算白写?
MySQL 的 SHA2() 是当前唯一推荐的内置哈希函数,但直接 SHA2('pwd', 256) 仍不安全——缺盐(salt)就是裸奔。
- 必须拼接随机盐值:
SHA2(CONCAT('pwd', 'x8a2f#k'), 256),盐不能写死,应每用户独立生成并存库 - 第二个参数只能是
224/256/384/512,写'256'或0会报错ER_WRONG_ARGUMENTS - 输出是 64 字符十六进制,字段必须设为
VARCHAR(64),小了就丢数据 - 别用
SHA2(email, 256)做唯一索引替代明文 email——哈希后无法模糊查询、无法关联其他系统
密码验证时最容易漏掉的三件事
哈希只是第一步,验证逻辑写错,前面全白干。
- 查库时必须用同样盐值重算一次:
WHERE password_hash = SHA2(CONCAT(?, users.salt), 256),不能把用户输入直接哈希后硬比对字段 - 避免时序攻击:别写
IF password_hash = SHA2(?, 256) THEN ...这种先查再比的逻辑,应统一走等值比较 - 字段字符集要用
utf8mb4_bin,防止大小写或空格归一化导致哈希不匹配
真正麻烦的从来不是调哪个函数,而是盐怎么生成、存哪、怎么读、怎么和业务流程咬合。哪怕用了 SHA2(, 256),盐值重复或硬编码在 SQL 里,安全水位照样归零。











