MD5、SHA-1、SHA-256:到 2026 年了,到底该用哪个
网上 90% 的哈希对比文章告诉你"SHA-256 比 MD5 更安全"——这是废话。真正的问题是:你要解决什么。给文件算指纹和给密码加盐用的根本不是同一类东西。这篇按场景倒推该用哪个。
先看场景表
不想看推理过程?直接对号入座:
| 你要干什么 | 用什么 | 原因 |
|---|---|---|
| 存用户密码 | bcrypt / Argon2 | SHA-256 都不行——见下文 |
| 文件下载校验 | SHA-256 | 抗碰撞 + 广泛工具支持 |
| API 请求签名(HMAC) | HS256 / HS512 | HMAC 的 H 就是 hash,外加 secret |
| 缓存键 / 数据去重 | MD5 也行 | 不需要安全性,要的是快 |
| Git 内部对象 | SHA-1(在迁 SHA-256) | 历史包袱,自己写代码别用 |
| 区块链 / 加密货币 | SHA-256 / Keccak-256 | 抗 collision 关键 |
| JWT 签名 | HS256 / RS256 | HMAC 或非对称 |
密码存储用 SHA-256(password + salt) 是常见错误。SHA-256 设计目标是快,但密码哈希要的是慢——慢到攻击者暴力破解算不起。bcrypt / Argon2 的 cost factor 让你能调节这个慢度。
什么是哈希——一句话
把任意长度的输入压成固定长度的"指纹"。两个不同输入得到相同输出叫"碰撞",理论上不可避免(鸽笼原理),但好的哈希算法让构造碰撞变得实际上不可行。
四个核心属性:
- 确定性 — 相同输入永远相同输出
- 不可逆 — 从输出反推输入要算上亿年
- 雪崩 — 改 1 比特,输出至少一半比特不同
- 抗碰撞 — 找两个不同输入 → 相同输出,应该极难
不同算法的差异主要在第 4 点上。
MD5:2026 年还能用,但要小心
1992 年发布,128 位(32 个 hex 字符)。
echo -n "hello" | md5sum
# 5d41402abc4b2a76b9719d911017c592 -
现状:2004 年王小云团队公布碰撞攻击,2008 年实战级 collision 出现。现在用 GPU 几秒就能构造两个 MD5 相同的不同文件。
但 MD5 没死透——以下场景仍合理:
- 缓存键:
md5(query_params)当 Redis key 完全 OK - 非对抗性去重:图床判断同一张图被传了两次
- 大文件分块标记:rsync 用过 MD5(已替换为更现代算法)
规则:只要不是对手能控制输入的场景,MD5 还能凑活用。
SHA-1:基本上别用
1995 年发布,160 位。Git 现在还在用——但 Git 也在迁。
echo -n "hello" | sha1sum
# aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d -
2017 年 Google 公布 SHAttered 攻击,用 9.2 万亿亿次哈希计算找到了第一个 SHA-1 碰撞。当时算力还很贵;2026 年的今天,AWS 上跑一周就能搞出来。
Git 2.43+ 已经支持 SHA-256 作为对象哈希,但生态还在迁移中。如果你自己写代码:跳过 SHA-1,直接 SHA-256。
SHA-256:现在的默认
2001 年作为 SHA-2 家族成员发布。256 位。在可预见的将来(至少十年)安全性没问题。
echo -n "hello" | sha256sum
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 -
什么时候用 SHA-512 而不是 SHA-256?64 位机器上 SHA-512 在某些场景更快(因为 64 位字操作更适合 64 位 CPU)。但输出长度翻倍带来传输/存储开销。一般默认 SHA-256。
密码存储为什么不用 SHA-256
这是新人最常错的地方。看到 SHA-256 标"安全",就拿来存密码:
// ❌ 错误示范
const hash = sha256(password + salt);
// 现代 GPU 每秒能算 100 亿次 SHA-256
// 8 位密码空间 ~10 万亿,几小时就能爆破
正确做法用为密码场景设计的算法:
// ✅ Node.js / bcrypt
import bcrypt from "bcrypt";
const hash = await bcrypt.hash(password, 12); // cost=12 大约 0.5 秒/次
// 攻击者爆破 1 个密码要算几小时,整库爆破不可行
// ✅ 更现代的选择:Argon2 (2015 PHC 比赛冠军)
import argon2 from "argon2";
const hash = await argon2.hash(password);
关键区别:cost factor。bcrypt cost=12 比 cost=10 慢 4 倍;硬件升级了你就 cost+=1,让攻击者也得跟着付出更多算力。SHA-256 没有这个参数。
"我们公司还在用 MD5 存密码"——这不是末日,但确实是技术债。迁移方案:用户下次登录时校验旧 MD5 通过后,重新用 bcrypt 哈希存进库,旧 MD5 字段清空。逐步替换,不影响存量用户。
各语言怎么算
JavaScript (浏览器)
async function sha256(text) {
const buf = new TextEncoder().encode(text);
const hash = await crypto.subtle.digest("SHA-256", buf);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
await sha256("hello");
// "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
Python
import hashlib
hashlib.sha256(b"hello").hexdigest()
# '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
命令行
# macOS / Linux
echo -n "hello" | sha256sum
# openssl 各平台都有
openssl dgst -sha256 file.txt
# 看大文件别 cat | sha256sum(多一次复制),直接:
sha256sum bigfile.iso
关于"算力涨了所以哈希都会被破"
常见的误解。哈希算法不是简单的"更长更安全"。SHA-256 的安全性建立在找碰撞需要尝试 2128 次这个数学难度上。摩尔定律就算继续 50 年,也不到这个数量级。
真正的威胁是数学突破——比如 SHA-1 被破是因为有人找到了构造碰撞的捷径。SHA-256 至今没有被发现这种捷径。但万一明天有人发现了——届时再换 SHA-3 或量子抗性算法。对工程来说,今天用 SHA-256 是对的决定。