Hash 算法横评:MD5/SHA-1/SHA-256/bcrypt 到底怎么选
"用 MD5 存密码" 这句话在 2026 年还会被新手写到代码里——然后等着哪天被脱库上头条。
Hash 算法看似是个简单的"输入到固定长度字符串"的转换,但用对算法 vs 用错算法的差距:前者撑得住几百亿次暴力破解,后者你的用户密码 5 分钟就被还原。
这篇文章把所有主流 Hash 算法横向拉一遍——能用什么、不能用什么、为什么——以及最容易出事的几个错误用法。
先说本质:Hash 不是加密
很多人混淆"Hash"和"加密",先把概念锁死:
| 维度 | Hash | 加密 |
|---|---|---|
| 方向 | 单向(不可逆) | 双向(可解密) |
| 输出长度 | 固定 | 与输入相关 |
| 目的 | 验证完整性、生成指纹 | 保护数据机密性 |
| 是否需要密钥 | 否(HMAC 除外) | 是 |
| 典型场景 | 密码存储、文件校验、数字签名 | 数据传输、文件加密 |
Hash 的核心特性:
- 确定性:相同输入永远得到相同输出
- 不可逆:从 Hash 反推原文在数学上不可行
- 雪崩效应:输入改一位,输出完全不同
- 抗碰撞:找两个不同输入产生相同 Hash 应该极难
通用 Hash 全家福
MD5:早该退休的老兵
| 项目 | 值 |
|---|---|
| 输出长度 | 128 位(32 个十六进制字符) |
| 设计年份 | 1991 |
| 状态 | 已破 |
已知问题:
- 2004 年王小云证明 MD5 抗碰撞性破产
- 2008 年研究者用 200 台 PS3 在 1 天内伪造了 CA 证书
- 现在普通电脑几秒就能制造碰撞
还能用在哪里:
- 非安全场景的完整性校验(下载文件对个 MD5 而已)
- 缓存键、数据去重(不涉及对抗)
绝对不能用在哪里:
- 密码存储
- 数字签名
- 任何安全相关用途
SHA-1:MD5 的难兄难弟
| 项目 | 值 |
|---|---|
| 输出长度 | 160 位(40 个十六进制字符) |
| 设计年份 | 1995 |
| 状态 | 已破 |
已知问题:
- 2017 年 Google 公布了 SHA-1 实际碰撞(SHAttered 攻击)
- 主流浏览器/CA 早就不再接受 SHA-1 证书
- Git 仍在用 SHA-1 但已经在迁移到 SHA-256
结论:和 MD5 一样,仅限非安全场景使用。
SHA-2 家族:当前主力
包含 SHA-224 / SHA-256 / SHA-384 / SHA-512:
| 算法 | 输出长度 | 速度 | 推荐度 |
|---|---|---|---|
| SHA-224 | 224 位 | 中 | 不常用 |
| SHA-256 | 256 位 | 中 | ⭐⭐⭐ 主流选择 |
| SHA-384 | 384 位 | 慢 | 特定场景 |
| SHA-512 | 512 位 | 64 位平台上更快 | ⭐⭐⭐ 长 Hash 用 |
用途:
- 文件完整性校验
- 数字签名
- 区块链(Bitcoin 就用 SHA-256)
- HMAC 基础
注意:SHA-256 不适合密码存储(见下文密码 Hash 章节)。
SHA-3:备胎也是好选择
2015 年标准化的新一代算法(基于 Keccak),与 SHA-2 在设计上完全不同——一旦 SHA-2 出问题,SHA-3 可以无缝替换。
| 算法 | 输出长度 | 性能 |
|---|---|---|
| SHA3-256 | 256 位 | 软件实现略慢于 SHA-256 |
| SHA3-512 | 512 位 | 同上 |
用途:
- 对未来 SHA-2 出问题有担忧时的选择
- 需要与特定生态对接(如以太坊用 Keccak-256)
BLAKE2 / BLAKE3:又快又安全
| 算法 | 特点 |
|---|---|
| BLAKE2 | 比 SHA-2 快几倍,安全性等同 |
| BLAKE3 | 进一步并行化,单线程超 1GB/s |
用途:
- 性能敏感的校验场景
- 内容寻址存储(IPFS 用 BLAKE2/3)
- 现代密码学库的默认选择(如 libsodium)
文件完整性校验实战
下载 Linux ISO 后核对官方 SHA-256:
输出与官网公布的对比,一致即原文件无篡改。
校验 Hash 比对的本质:MD5 还能用是因为这种"无对抗"场景——你只是怕下载链路出错,不是怕有人伪造文件。但凡涉及对抗(攻击者会想办法制造碰撞),用 SHA-256 或更高。
密码 Hash:通用 Hash 不能干这事
为什么 SHA-256 不能存密码
理由很反直觉:SHA-256 太快了。
现代 GPU 一秒能算 100 亿次 SHA-256(这是 Bitcoin 矿机的工作)。对密码 Hash 来说"快"是致命的——意味着攻击者拿到你的 Hash 库后能极速暴力破解:
| 密码长度 | 字符集 | GPU 破解时间 |
|---|---|---|
| 6 位 | 数字+字母 | < 1 秒 |
| 8 位 | 数字+字母 | 几分钟 |
| 10 位 | 完整字符集 | 几天 |
加上彩虹表攻击(预计算的 Hash 库),常见密码的 SHA-256 几乎可以瞬间反查。
历史上的惨痛教训
| 事故 | 用了什么 | 后果 |
|---|---|---|
| Adobe 2013 (1.5 亿账号) | 3DES 加密(不是 Hash) | 破解后大量密码明文泄露 |
| LinkedIn 2012 (1.65 亿账号) | 未加盐 SHA-1 | 90% 密码 6 天内被还原 |
| Equifax 2017 (1.47 亿用户) | 未加密文本存储等 | 公司市值蒸发 50 亿美元 |
教训只有一条:密码必须用专门的密码 Hash 算法,不是通用 Hash。
专门的密码 Hash 算法
设计思想:故意做慢——让一次 Hash 计算耗时几十到几百毫秒,攻击者爆破速度被压到正常 Hash 的几百万分之一。
| 算法 | 设计年份 | 推荐度 | 备注 |
|---|---|---|---|
| bcrypt | 1999 | ⭐⭐⭐ | 老牌可靠,工作因子可调 |
| scrypt | 2009 | ⭐⭐ | 内存密集,抗 GPU |
| Argon2id | 2015 | ⭐⭐⭐ | 现代首选,Password Hashing Competition 冠军 |
| PBKDF2 | 2000 | ⭐ | 标准化最早,抗 GPU 弱,仅在合规要求时用 |
推荐排序:
- 新项目:Argon2id 优先
- 已有 bcrypt 系统:继续用就行,bcrypt 仍然安全
- PBKDF2:除非要过 FIPS 合规,否则不要
bcrypt 用法
关键参数:rounds(工作因子)默认 10-12,每加 1 计算时间翻倍。推荐:
- 普通业务:12
- 高敏感场景:14+
- 测试当前服务器上算一次 Hash 不超过 250ms 为佳
Argon2id 用法
OWASP 2026 推荐参数:memory_cost=19 MiB, time_cost=2, parallelism=1(最低基准),按服务器性能上调。
关于"盐"(Salt)
bcrypt 和 Argon2 都自动加盐,输出格式里已经包含盐——你不用单独存。
但如果你看到这种代码,立即重构:
直接换 bcrypt 或 Argon2 就行。
HMAC:带密钥的 Hash
普通 Hash 任何人都能算,HMAC 加入密钥——只有持有密钥的人才能算出正确的 Hash。
用途:
- API 请求签名(防篡改 + 验证身份)
- JWT 的 HS256 算法
- Webhook 验签
安全要点:
- 比较签名时用
hmac.compare_digest(),不要用==——避免时序攻击 - 密钥至少 256 位随机
算法选型决策树
5 大典型错误
错误 1:用 MD5/SHA-1 存密码
立即换成 bcrypt 或 Argon2。已经在线上的:用户下次登录时验证旧 MD5,验证通过后立即 rehash 到新算法。
错误 2:自己拼盐自己 Hash
通用 Hash 太快,无论怎么加盐都防不住 GPU 暴力破解。用专门密码 Hash 算法。
错误 3:HMAC 用等号比较
字符串 == 比较找到第一个不同字符就退出,攻击者可以根据响应时间逐位猜测签名。
错误 4:Hash 当加密用
需要可逆?那不是 Hash 的活,是加密的活。用 AES-GCM、ChaCha20-Poly1305 这类对称加密。
错误 5:把 Hash 当唯一标识但截断了
8 位十六进制 = 32 位空间 = 生日攻击下 6.5 万条数据就有 50% 碰撞概率。要么用全长,要么用专门的 UUID。
性能参考
在现代 x86_64 CPU 单线程的吞吐量(仅供参考,硬件加速、SIMD 实现会显著提升):
| 算法 | 吞吐量 |
|---|---|
| MD5 | ~600 MB/s |
| SHA-1 | ~700 MB/s |
| SHA-256 | ~400 MB/s(带 SHA-NI 指令可到 1.5 GB/s) |
| SHA-512 | ~600 MB/s(64 位机器上反超 SHA-256) |
| BLAKE2b | ~1 GB/s |
| BLAKE3 | 单线程 ~1.5 GB/s,多线程线性扩展 |
| bcrypt (cost=12) | ~3 次/秒(故意慢) |
| Argon2id (64MB) | ~30 次/秒(故意慢且吃内存) |
结论:通用场景 BLAKE3 性能王者;密码场景就是要慢——慢是 feature 不是 bug。
总结
把这张速查图钉在脑子里:
| 场景 | 用什么 |
|---|---|
| 密码存储 | Argon2id > bcrypt |
| 文件校验(对抗) | SHA-256 / BLAKE3 |
| 文件校验(非对抗) | MD5 也行(但建议 SHA-256) |
| API 签名 | HMAC-SHA256 |
| 通用指纹 | SHA-256 / BLAKE3 |
| 缓存键、去重 | MD5 / xxHash / BLAKE3 |
最重要的一条:通用 Hash(MD5/SHA-2/SHA-3/BLAKE)永远不要直接用于密码存储。这条记不住,下次脱库上头条的就可能是你的公司。
需要生成 Hash 时用站内的 Hash 生成器,需要生成强密码或密钥时用 密码生成器——两个工具配合,覆盖日常 80% 的密码学需求。