Skip to content
crypto2026-07-256 分钟阅读

"我该用 MD5 还是 SHA-256?" 这个问题的答案,完全取决于你要保护的是什么。把 MD5 用在错误的地方,会留下安全漏洞;把 SHA-256 用在 MD5 就够用的地方,会徒增复杂度(不过老实说,性能差异现在很少是真正的问题)。

这篇指南直接切入正题:两种算法各自做什么、为什么 MD5 在安全场景下已经不可用、它在哪些场景仍然完全没问题,以及一个简单的选择决策框架。

MD5 和 SHA-256 的工作原理(简述)

两者都是密码学哈希函数——它们接收任意大小的输入,输出固定长度的"摘要"(digest)或"哈希"。相同的输入总是产生相同的哈希。输入哪怕只改变一个比特,输出也会变成完全不同的哈希。

MD5(Message Digest 5):

  • 1992 年由 Ronald Rivest 发布
  • 产生 128 位(16 字节)哈希,显示为 32 个十六进制字符
  • 示例:echo -n "hello" | md55d41402abc4b2a76b9719d911017c592

SHA-256(Secure Hash Algorithm 256-bit):

  • 2001 年由 NIST 作为 SHA-2 家族的一部分发布
  • 产生 256 位(32 字节)哈希,显示为 64 个十六进制字符
  • 示例:echo -n "hello" | shasum -a 2562cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

两者都是单向函数:无法通过哈希反推出原始输入。两者都是确定性的:相同输入永远得到相同输出。

关键差异在于它们抵抗碰撞攻击的能力。

为什么 MD5 在安全场景下已经"坏了"

碰撞(collision)是指两个不同的输入产生相同的哈希。一个安全的哈希函数,找到碰撞在计算上应当是不可行的。

MD5 没能守住这条底线。2004 年,研究人员演示了对 MD5 的实际碰撞攻击。到 2008 年,攻击者利用证书签名流程中的 MD5 碰撞伪造了一张恶意 SSL 证书。2012 年,Flame 蠕虫利用 MD5 碰撞伪造了微软的代码签名证书。

实践中的含义:

攻击者可以构造两个具有相同 MD5 哈希的不同文件。如果你的系统用 MD5 哈希来校验完整性或真实性,攻击者就能用一个产生相同哈希的恶意文件替换掉合法文件。

# 两份不同的 PDF,MD5 哈希相同(研究人员已演示)
# 文件 A:合法文档
# 文件 B:恶意文档,但 MD5 相同
md5(file_a) == md5(file_b)  # True —— 但内容不同

截至 2026 年,SHA-256 还没有已知的实际碰撞攻击。理论上最优的攻击大约需要 2^128 次运算,远超任何可预见的计算能力。

MD5 在哪些场景仍然可以接受

MD5 并非一无是处。当不需要抗碰撞——即攻击者没有动机或能力针对你的具体场景构造碰撞时,使用 MD5 是没问题的。

文件完整性校验(非对抗场景):

校验下载文件是否完整传输(而非是否被篡改):

# 用发布方提供的校验和验证下载文件
md5sum ubuntu-26.04-desktop-amd64.iso
# 与下载页面给出的哈希对比

如果你只是检查意外损坏(比特翻转、传输不完整),MD5 完全够用。但如果需要确认文件没有被攻击者"故意修改",请使用 SHA-256。

缓存键和去重:

把哈希用作快速查找键,并且即使发生碰撞也能优雅处理:

import hashlib

def get_cache_key(content):
    # 这里用 MD5 没问题 —— 最坏情况只是缓存未命中
    return hashlib.md5(content).hexdigest()

如果发生碰撞,无非就是缓存未命中或多存了一份冗余副本,没有任何安全影响。

非安全场景的文件去重:

备份工具跳过未修改的文件:

# rsync 风格:跳过内容哈希未变化的文件
find . -type f -exec md5sum {} \; | sort > manifest.md5

遗留系统兼容性:

一些老的 API、包管理器或文件格式只支持 MD5 校验和。这种情况下你只能继续用——但在任何可能的地方加上 SHA-256 校验。

哪些场景必须使用 SHA-256(或更强算法)

数字签名和证书:

任何对数据签名并验证签名的系统,都必须使用抗碰撞的哈希。SHA-256 是最低标准:

# 对发布产物签名
openssl dgst -sha256 -sign private_key.pem -out release.sig release.tar.gz
openssl dgst -sha256 -verify public_key.pem -signature release.sig release.tar.gz

密码存储(但不能直接用):

千万不要用裸 MD5 裸 SHA-256 来哈希密码。两者都太快,在现代 GPU 面前暴力破解毫无门槛。请使用专门设计的密码哈希函数:

# 错误 —— 永远不要这样做
import hashlib
password_hash = hashlib.sha256(password.encode()).hexdigest()

# 正确 —— 使用 bcrypt、scrypt 或 argon2
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

Argon2id 是目前密码哈希的黄金标准,bcrypt 仍然被广泛使用且经过充分验证。这些函数的关键特性是"慢"——它们在计算上故意很昂贵,使暴力破解变得不可行。

区块链和加密货币:

比特币和大多数区块链系统使用 SHA-256 进行区块哈希和工作量证明。抗碰撞特性对链的完整性至关重要。

API 请求签名和 HMAC:

在为 API 请求签名或生成 HMAC token 时:

import hmac
import hashlib

# 用于 API 认证的 HMAC-SHA256
signature = hmac.new(
    secret_key.encode(),
    message.encode(),
    hashlib.sha256
).hexdigest()

Git 和内容寻址存储:

Git 已经从 SHA-1 迁移到 SHA-256 作为对象哈希。任何攻击者可能注入恶意内容的内容寻址系统,都应使用 SHA-256。

合规与监管要求:

PCI-DSS、HIPAA、SOC 2 以及大多数合规框架都明确禁止将 MD5 用于密码学用途,并要求使用 SHA-256 或更强算法。

性能对比

随着硬件 SHA 扩展指令(Intel SHA-NI、ARM Crypto Extensions)的普及,MD5 和 SHA-256 的速度差距已经显著缩小:

| 算法 | 吞吐量(带硬件加速的现代 CPU) | 输出大小 | |-----------|--------------------------------------|-------------| | MD5 | ~1.5 GB/s | 128 位 | | SHA-256 | ~1.2 GB/s(带 SHA-NI) | 256 位 | | SHA-256 | ~500 MB/s(纯软件实现) | 256 位 |

在支持 SHA-NI 的现代硬件上(2017 年以来大多数 CPU 都支持),SHA-256 的速度已经快到几乎所有应用都无需在意性能差距。你需要达到每秒几十 GB 的哈希吞吐,MD5 的速度优势才有意义——而到了那个量级,你需要回答的是更大的架构问题。

对于常见场景——哈希 API 负载、校验下载文件、生成缓存键——差异只有微秒级。请根据安全需求选择,而不是速度。

决策框架

用这个流程来判断:

1. 是否用于安全场景?(认证、签名、证书、对抗性完整性校验)

  • 是 → 至少使用 SHA-256,绝不用 MD5。
  • 否 → 进入问题 2。

2. 是否用于密码存储?

  • 是 → 两者都不要用,请用 Argon2id 或 bcrypt。
  • 否 → 进入问题 3。

3. 攻击者是否能从构造碰撞中获益?(例如用匹配合法哈希的恶意文件进行替换)

  • 是 → 使用 SHA-256。
  • 否 → MD5 可以接受(缓存键、非对抗性校验和、去重)。

4. 是否有合规或监管要求?

  • 是 → 按标准来(几乎都是 SHA-256+)。
  • 否 → 基于问题 1-3 自己判断。

拿不准时,就用 SHA-256。 性能代价可以忽略,输出仍然紧凑(64 个十六进制字符),而且你永远不用担心某个"非安全"用例日后是否会变成安全相关。

在本地生成哈希

无论你需要为缓存键生成 MD5 校验和,还是为文件校验生成 SHA-256 哈希,都可以在不把数据发送到服务器的情况下完成。

SHA-256 哈希生成器MD5 哈希生成器 都完全使用 Web Crypto API 在你的浏览器中处理输入。你的文本、文件或 API 负载永远不会离开你的机器——这在哈希 API 密钥、个人数据或专有代码等敏感内容后再发给第三方时尤为重要。

命令行快速哈希:

# SHA-256
echo -n "your input" | shasum -a 256

# MD5
echo -n "your input" | md5

# 文件哈希
shasum -a 256 important-file.pdf
md5sum important-file.pdf  # Linux

总结一下:MD5 是适合非对抗场景的快速校验和;SHA-256 是任何安全相关场景的基线;至于密码,两者都不要用——请选择 Argon2id 或 bcrypt。拿不准时,SHA-256 是没有副作用的安全默认选择。


ad