MD5 到底是什么
很多人把 MD5 叫做"MD5加密",这个说法从一开始就是错的。
MD5 是一种哈希函数(Hash Function),不是加密算法。两者有本质区别:
- 加密:可逆操作,有密钥,能解密还原原始数据
- 哈希:不可逆操作,无密钥,理论上无法从结果推回原始数据
MD5 的作用是把任意长度的输入,变成一个固定 128 位(32个十六进制字符)的输出,称为"摘要"或"指纹"。
MD5("hello") = 5d41402abc4b2a76b9719d911017c592
MD5("hello!") = 9b56e4f280d7b27a6c8d0c11d5a8cb7d
MD5("一篇很长的文章...") = d41d8cd98f00b204e9800998ecf8427e
三个特性:
- 单向性:无法从哈希值逆推原始内容
- 固定长度:无论输入多长,输出始终 32 位
- 雪崩效应:输入改动一个字节,输出完全不同
MD5 能被"破解"吗
严格来说,MD5 无法被"解密"——因为它不是加密。但它可以被暴力破解或查表攻击。
暴力破解
最简单的思路:把常见密码逐个计算 MD5,和目标哈希值对比。
计算 MD5("123456") = e10adc3949ba59abbe56e057f20f883e ← 匹配!
现代 GPU 每秒可以计算数十亿次 MD5,123456、password、qwerty 这类常见密码在不到一秒内就能找到。
彩虹表攻击
暴力破解需要实时计算,而彩虹表是预先计算好的海量明文-哈希值对照表,空间换时间。
攻击者拿到一个 MD5 哈希值,直接在表里查找,瞬间得到原始密码。网上有公开的 MD5 彩虹表,覆盖数百亿条常见密码和短字符串组合。
实际上,很多"MD5在线解密"网站的原理就是这个——它们维护了一张巨大的哈希-明文数据库,输入哈希值查表返回结果,不是真正的"解密"。
MD5 碰撞
2004年,研究人员找到了 MD5 的碰撞攻击方法:可以构造出两个不同的输入,产生完全相同的 MD5 值。这从根本上动摇了 MD5 作为完整性校验工具的可信度。
文件A 和 文件B 内容完全不同,但 MD5 值完全相同
这意味着攻击者可以伪造一个与合法文件 MD5 值相同的恶意文件,绕过完整性校验。
为什么还有人用 MD5 存密码
历史原因。MD5 在 1991 年发布时被认为足够安全,大量早期系统将其用于密码存储。随着计算能力的提升和攻击方法的演进,MD5 的安全性早已不够,但遗留系统的迁移成本很高,导致至今仍有系统在用。
2012年 LinkedIn 数据泄露事件中,约 650 万条密码以未加盐的 SHA-1 哈希存储;更早的数据泄露中,大量网站使用的正是裸 MD5。泄露后,攻击者在数小时内就破解了绝大多数密码。
正确的密码存储方案
加盐(Salt)
给每个密码在哈希前拼接一段随机字符串(盐值),使得相同的密码产生不同的哈希结果,从而让彩虹表完全失效。
salt = "xK92mP" // 每个用户随机生成,存入数据库
hash = MD5(password + salt)
但即便加盐,MD5 本身计算太快,GPU 暴力破解仍然可行。
bcrypt:专为密码存储设计
bcrypt 是目前最主流的密码哈希方案,有几个关键特性:
1. 内置盐值:每次哈希自动生成随机盐,无需手动处理。
2. 计算成本可调:通过 cost factor 参数控制哈希运算的计算量,随硬件提升可以相应调高,保持破解难度。
3. 故意很慢:正常用户登录只需验证一次,慢一点无所谓;但攻击者需要暴力尝试数十亿次,慢就是致命的。
import bcrypt
# 注册:生成哈希
password = b"user_password"
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))
# 存入数据库的是 hashed,不是原始密码
# 登录:验证
bcrypt.checkpw(password, hashed) # 返回 True/False
Argon2:更现代的选择
Argon2 是 2015 年密码哈希竞赛的冠军算法,在 bcrypt 基础上增加了内存占用控制,进一步提升了对 GPU 和 ASIC 暴力破解的抵抗力。新项目首选 Argon2id。
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=2, memory_cost=65536, parallelism=2)
hashed = ph.hash("user_password")
ph.verify(hashed, "user_password") # 验证
scrypt
与 Argon2 类似,也是内存密集型哈希,Node.js 标准库内置支持,适合 JavaScript 后端。
MD5 现在还能用在哪里
MD5 不适合安全场景,但在以下非安全场景中仍然合理:
文件完整性校验(非安全环境)
下载文件后对比 MD5 值,确认文件未被损坏(注意:不能防止有意篡改,只能检测传输错误)。
# Linux/macOS
md5sum filename.zip
# macOS
md5 filename.zip
生成唯一标识符
对内容取 MD5 作为缓存 key、去重 ID 等,不涉及安全的场景。
数据库内容去重
对大文本字段取 MD5 建索引,快速判断是否重复。
非安全场景的数据指纹
日志系统、数据管道里对数据做快速摘要,用于追踪和对比。
一句话总结
| 场景 | 推荐方案 |
|---|---|
| 用户密码存储 | bcrypt 或 Argon2id |
| 文件完整性校验(安全) | SHA-256 |
| 文件完整性校验(非安全) | MD5 可用 |
| 数字签名 | RSA + SHA-256 |
| 缓存 Key / 去重 ID | MD5 可用 |
密码存储永远不要用 MD5,不管加不加盐。
在线工具
如果你需要计算一段文本的 MD5 值用于数据校验或测试,可以使用 toolshu.com 的 MD5 在线加密工具,支持 16 位和 32 位输出,大小写均可,在浏览器本地运算不上传数据。



加载中...