SHA-256 和 MD5 到底有什么区别,为什么密码不能直接用它们
下载文件时页面会给一串 SHA256 值,登录时后台存的是密码的哈希——这两个场景看起来一样,其实要求完全不同。混用是安全事故的常见来源。
哈希函数的四个必备特性
- 定长输出:不管输入是 1 字节还是 1GB,输出长度固定(SHA-256 永远是 64 个十六进制字符)
- 确定性:同样的输入永远得到同样的输出
- 雪崩效应:改一个比特,输出面目全非
- 单向性:从哈希值反推原文在计算上不可行
注意这里没有"不可碰撞"——数学上碰撞必然存在(输入无限、输出有限),只是要求"找到碰撞在计算上不可行"。
MD5 为什么不能用
MD5 输出 128 位。2004 年王小云团队给出了实用的碰撞攻击方法,如今几秒钟就能构造出两个 MD5 相同但内容不同的文件。
这意味着:
- ❌ 不能用 MD5 校验下载文件的完整性(攻击者可以篡改文件同时保持哈希一致)
- ❌ 不能用 MD5 做数字签名
- ❌ 不能用 MD5 存密码
- ⚠️ 有些老系统的"文件校验"还在用 MD5,只能防传输错误,不能防恶意篡改
SHA-1 更惨——Google 在 2017 年实际构造出了 SHA-1 碰撞(SHAttered 攻击),两个不同的 PDF 得到相同 SHA-1。所以现在浏览器和 Git 都在淘汰 SHA-1。
SHA-256 好在哪里
SHA-2 家族(SHA-224/256/384/512)目前没有已知的实用攻击。SHA-256 输出 256 位,暴力破解需要的计算量在可预见的未来不可行。
本站在计算哈希时用的是浏览器原生的 crypto.subtle.digest(),由底层 C++ 实现,速度快且不经过任何网络。
但存密码,SHA-256 也不够
这是最容易被误解的地方。SHA-256 设计目标是快——GPU 每秒能算几十亿次。这对校验文件是优点,对存密码是致命缺点。
攻击者拿到数据库后,可以用一张"常用密码哈希表"(彩虹表)直接反查,或者用显卡暴力枚举。8 位纯数字密码,现代显卡几秒钟就能穷举完。
正确做法:用专门的密码哈希函数
| 函数 | 特点 | 推荐度 |
|---|---|---|
| Argon2id | 内存硬,抗 GPU,2015 年密码哈希竞赛冠军 | ⭐⭐⭐⭐⭐ 首选 |
| bcrypt | 成熟稳定,可调 cost 因子 | ⭐⭐⭐⭐ 广泛可用 |
| scrypt | 内存硬,但参数调优较麻烦 | ⭐⭐⭐ |
| SHA-256 + 盐 | 加盐只防彩虹表,不防暴力枚举 | ⭐⭐ 不够 |
| MD5 / SHA-1 | 已被攻破 | ❌ 禁止 |
核心区别:Argon2/bcrypt 是故意设计得慢(可调参数让它耗时 100ms),所以暴力枚举的成本被放大几百万倍。SHA-256 做不到这一点。
校验下载文件时怎么用
正确流程:
- 从官方渠道获取哈希值(不要从同一个下载页拿,否则被篡改时两个一起改)
- 本地计算文件的 SHA-256
- 逐字符比对
Windows 下可以用 certutil -hashfile 文件名 SHA256,Linux/macOS 用 sha256sum 文件名。
一句话总结:校验完整性用 SHA-256,存密码用 Argon2id 或 bcrypt,MD5 只在完全不涉及安全的老场景里出现。
要算一段文本的哈希?
打开哈希工具