7AA7 Blog

文件校验入门:MD5、SHA-256 与完整性验证的正确用法

沈叙白 UID:72
2026-10-05 14:50
51 3 1

从网上下载一个安装包,旁边往往附一行”校验值”;传一份数据到对方手里,双方要比对一段哈希。这些场景用的都是哈希函数——把任意长度的输入映射成固定长度的摘要。它看着简单,但”该用哪个算法、校验到底验的是什么”这两件事,很多人其实一直靠惯性在做。

一、哈希函数在保证什么

一个用于完整性校验的哈希函数,需要满足几条性质:

  • 确定性:同样的输入永远得到同样的摘要,跨机器、跨平台一致。
  • 抗原像(单向性):从摘要反推输入在计算上不可行。
  • 抗第二原像:给定一个文件,很难找到另一个文件产生相同摘要。
  • 抗碰撞:很难主动构造出两个摘要相同的文件。

摘要长度决定了输出空间的大小。SHA-256 的摘要是 256 比特,可能取值约 2 的 256 次方,随机碰撞的概率低到可以忽略。注意”抗碰撞”和”抗第二原像”是两回事:前者防的是攻击者刻意制造两个同摘要文件,后者防的是为已有文件找到替代品。完整性校验同时依赖这两条。

哈希验证的是”内容是否一致”,不验证”内容是谁的”——这一点后面会细说。

二、MD5 与 SHA-1 的现状

MD5(128 比特摘要)和 SHA-1(160 比特摘要)是历史最悠久的两个算法,如今它们的地位是”算法层面已被攻破,但仍在一些老场景里服役”。

客观地讲:

  • MD5 的碰撞攻击已经很成熟。构造两个内容不同、MD5 相同的文件在计算上是可行的,成本也早已降到普通研究者可负担的范围。因此 MD5 不能用于任何对抗性场景——数字签名、证书、防篡改校验都必须换算法。
  • SHA-1 的实际碰撞攻击也已有公开案例。学术界和工业界普遍把它视为不应再用于安全用途的算法。
  • 但”被攻破”不等于”完全无用”。在非对抗性场景里,比如排查下载损坏、对比两份缓存文件是否一致,MD5 依然快速有效——没有攻击者在刻意构造碰撞时,它做”找不同”的工作完全够用。

区分清楚场景很重要:文件在可信内部环境里做去重、做缓存键,MD5/SHA-1 的速度优势是实打实的;文件来自不可信来源、用于决定”能不能执行/能不能上线”,就必须用现代算法。混用这两类场景,才是真正的风险来源。

三、SHA-256 的适用场景

SHA-256 属于 SHA-2 家族,摘要 256 比特,目前没有任何实用的碰撞攻击。需要完整性或防篡改的地方,它是默认选择:

  • 软件发布包的官方校验值;
  • 容器镜像、依赖包的内容摘要;
  • 数字签名里被签名的那个摘要;
  • 可执行文件、固件更新包的完整性验证。

它的速度对大多数场景足够快;如果是 GB 级以上的超大文件,也可以考虑并行/硬件加速的实现,但对常规软件包来说性能差异可以忽略。SHA-3 系列提供了另一套不同结构的备选,二者并存,按生态里的惯用约定选择即可。

四、哈希校验 vs 签名校验

这是最容易被混淆的一对概念:

  • 哈希校验回答:”这个文件的内容,和我手里的参考摘要一致吗?”
  • 签名校验回答:”这个文件确实是那个发布者发布的吗?内容有没有被改过?”

区别在于信任锚。哈希值如果和文件放在同一个下载页面上,攻击者改了文件顺手改了哈希,校验就形同虚设——你只是在用一个不可信的参考值去核对一个不可信的文件。签名引入了非对称密钥:发布者用私钥对摘要签名,验证方用公开的公钥验签,攻击者没有私钥就无法伪造出合法签名。

所以实践中:

  1. 从独立可信的渠道获取校验值或签名(官方签名通道、独立发布的校验值列表),别只信文件旁边的那一行。
  2. 涉及执行、上线、刷机等高风险用途,优先验签,哈希作为辅助。
  3. 仅是”文件传输有没有损坏”,比对哈希就够了,不必上签名。

五、下载完整性验证的实操

拿到文件和官方校验值之后,本地计算摘要再比对。常见命令:

# Linux / macOS
sha256sum package.tar.gz
shasum -a 256 package.tar.gz     # macOS 常见

# Windows(自带)
certutil -hashfile package.zip SHA256

流程可以固定成四步:

  1. 从官方渠道下载文件与校验值(尽量让二者来源相互独立)。
  2. 用上面的命令本地计算摘要。
  3. 与官方校验值逐字符比对,大小写差异可忽略,字符内容必须完全一致。
  4. 不一致就删除文件重新下载,并检查下载渠道——传输损坏和中间人篡改都可能导致不一致,前者重试即可,后者要换渠道。

比对时别用肉眼扫:一串 64 位十六进制里错一个字符,肉眼很难发现。用脚本或命令做字符串比较最稳妥。

# Linux 示例:把官方值存入文件后自动校验
echo "e3b0c442...package.tar.gz" | sha256sum -c -

六、大文件:分块哈希与增量校验

几百 MB 以上的文件,整体重算哈希的代价不小。两个常用思路:

  • 分块哈希:把文件按固定大小切块,对每块单独算摘要,再把块摘要列表聚合成一个总摘要(Merkle 树就是这个思路的结构化形式)。好处是校验可以按块并行,也便于定位出问题的是哪一段。
  • 增量校验:断点续传、rsync 同步这类场景,只需要对”变化的部分”重算摘要,未变的块沿用旧摘要。配合块级摘要记录,同步工具可以快速判断哪些块需要重传,而不必每次扫全量。

分块的块大小要在校验粒度和元数据开销之间取舍:块越小定位越准,但摘要列表越长。实际系统里常见的取值从几十 KB 到几 MB 不等,按文件特征和网络条件调整。

另一个配合大文件的实践是把摘要本身纳入版本管理:每次发布生成的校验值列表随版本号归档,回溯排查”某个历史版本的包有没有问题”时,直接对照当时的记录,而不是事后重新拼凑参考值。团队内部共享下载源时,这一层记录能省下大量重复比对的时间。

文件校验这件事,算法选择只是第一步;更关键的是想清楚”我在防什么”——防损坏,哈希够用;防篡改,必须让参考值或签名来自独立的信任源。把这两件事分清楚,绝大多数完整性验证的坑就都绕开了。

463Views
51Likes
3Comments
3Participants
7 minread time

Comments (3)

  • Riven · 2026-10-05 17:50

    团队里刚好在为这个吵架,这篇文章可以拿去当依据。

    Reply
  • 朔风 · 2026-10-06 00:50

    文中那张表总结得好,一眼就看明白了。

    Reply
  • Corin · 2026-10-06 07:50

    结构清晰,适合反复读。

    Reply