文件哈希:MD5、SHA-1、SHA-256 的区别与下载校验方法

文件哈希是根据文件内容计算的固定长度值,通常用于将下载的文件与参考副本进行比较。相同的字节和算法会产生相同的结果,但理论上不同的文件也可能共享同一个哈希值。对于日常文件验证,当发布者提供时,优先使用 SHA-256,并检查参考值的来源。

文件哈希表示什么?

哈希函数计算一个称为哈希值或摘要的汇总。MD5、SHA-1 和 SHA-256 都有固定的输出长度:使用相同算法时,小文档和大型安装程序产生的摘要长度相同。摘要不是可以用来重建文件的压缩副本。NIST 对哈希函数的概述 解释了这些属性及相关的安全要求。

普通的文件哈希工具读取文件内部的字节,而不是其名称或文件夹位置。仅仅重命名文件而不改变其内容,哈希值不会改变。相反,两个显示相同文本的文档可能因为换行符、字符编码或文件内部存储的元数据不同而包含不同的字节。

哈希可以被描述为指纹,但它并不是绝对唯一的标识符。当不同的输入产生相同的摘要时,就会发生碰撞。安全的密码学哈希函数旨在使找到这种输入变得不切实际。MD5 和 SHA-1 不再满足抗碰撞应用的安全要求。

MD5 与 SHA-1 与 SHA-256

MD5 代表消息摘要算法 5;SHA 代表安全哈希算法。SHA-256 属于 SHA-2 家族并生成 256 位。工具通常以十六进制文本显示结果。每个十六进制字符代表四位,因此长度如下:

算法 摘要大小 十六进制长度 文件验证选择
MD5 128 位 · 16 字节 32 个字符 可能需要比较旧的校验和,但不应用于防止恶意篡改。
SHA-1 160 位 · 20 字节 40 个字符 可以与旧版参考值进行比较;避免将其用于新的安全应用。
SHA-256 256 位 · 32 字节 64 个字符 当发布者提供 SHA-256 值时,是日常下载完整性检查的实用选择。

MD5的安全局限及抗碰撞性问题在RFC 6151的MD5安全性考虑中进行了讨论。SHA规范出现在NIST的安全哈希标准中。检测意外传输错误和防御能够篡改文件的攻击者是不同的需求。

始终比较相同算法的哈希值。本地计算的SHA-256值不能与发布的MD5值进行比较。此外,256位输出并不意味着在面对所有类型攻击时具有256位强度。请参阅NIST的算法和安全强度指导,了解SHA-1的限制以及不同攻击类型之间的差异。

当一个字符发生变化时会发生什么?

这个 Python 示例计算 ASCII 字节 abc 和 abC 的 SHA-256 值。只有最后一个字符不同,且两个输入都不包含尾随换行符。显示的输出已在 Python 3.12 中验证;两个摘要都包含 64 个十六进制字符。

import hashlib

for data in (b"abc", b"abC"):
    print(data.decode("ascii") + ": " + hashlib.sha256(data).hexdigest())

输出:

abc: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
abC: 0a2432a1e349d8fdb9bfca91bba9e9f2836990fe937193d84deef26c6f3b8f76

这些看起来相似的输入产生了非常不同的摘要。该示例并不能证明每一对不同的输入都必须有不同的哈希值。相同输入的确定性输出、可能出现的碰撞以及对故意攻击的抵抗力是不同的性质。

如何验证下载的文件

完整性验证检查数据是否与参考值不同。仅计算新的摘要并不是验证:你需要一个可信的参考哈希来进行比较。

  1. 从发布者的官方下载页面或其他可信的分发渠道获取参考哈希。
  2. 确认操作系统、CPU架构、版本和文件名与下载内容匹配。检查参考使用的算法。
  3. 等待下载完成,然后使用相同的算法计算其哈希。在读取文件时不要修改或覆盖该文件。
  4. 对于 SHA-256,比较所有 64 个十六进制字符,而不仅仅是开头部分。大写和小写十六进制字母表示相同的数值。
  5. 如果数值不同,不要运行或安装该文件。重新检查比较目标,然后从官方网站重新下载,并重复验证。

如果攻击者可以替换文件及其参考哈希值,匹配的数值并不能确定是谁提供的。匹配只是与参考数据的比较,并不能证明文件没有恶意软件。当提供签名校验和或数字签名时,请按照发布者的说明,并使用受信任的公钥进行验证。

Windows、Linux 和 macOS 的 SHA-256 命令

example.iso 以下是示例文件名。请将其及路径替换为您实际的下载,并对包含空格的路径加引号。这些命令读取文件以计算其摘要;它们不会更改文件内容。

Windows:在 PowerShell 中使用 Get-FileHash

从“开始”菜单打开 PowerShell 并运行以下命令。-LiteralPath 会按字面处理路径,而不会解释通配符字符。-Algorithm SHA256 明确选择算法。

Get-FileHash -LiteralPath 'C:\Downloads\example.iso' -Algorithm SHA256 | Format-List

检查 Algorithm、Hash 和 Path 字段。SHA-256 是默认值,但指定它可以使比较更清晰。微软的 Get-FileHash 文档 描述了支持的算法和输出。如果找不到文件,请在文件资源管理器中检查其实际路径和扩展名。

Linux:sha256sum

在安装了 GNU Coreutils sha256sum 的环境中,打开终端并运行此命令。通常的输出包括摘要,后跟文件名。

sha256sum "/home/user/Downloads/example.iso"

如果发布者提供 GNU 格式的 SHA256SUMS 文件,请将其与要验证的文件放在同一文件夹中,在该文件夹中打开终端,然后使用下面的命令检查列表。列表中命名的路径必须存在。如果你只下载了其中的一部分条目,完整列表可能会报告缺失的文件。

sha256sum --check SHA256SUMS

匹配的条目会作为 OK 报告;不匹配的条目会报告为失败。校验和列表本身也必须来自可靠来源。请参考 GNU SHA-2 实用程序手册 以获取命令和检查选项。如果命令不存在,请检查你的发行版是否安装了 Coreutils。

macOS: shasum

如果您的终端中有 shasum,请使用 -a 256 明确选择 SHA-256。没有该选项,shasum 默认使用 SHA-1,这可能导致算法不匹配。

shasum -a 256 "/Users/user/Downloads/example.iso"

要验证兼容的校验和列表,请使用 shasum -a 256 -c SHA256SUMS。shasum 维护者的文档 解释了算法选择和 -c。这些 macOS 指南基于工具的文档,而不是在 macOS 上执行;下方的 Python 方法是在工具不可用时的替代方案。

使用 Python 计算大文件的 SHA-256

安装 Python 3 后,您可以使用标准库 hashlib 模块。将此代码保存为 hash-file.py。它以二进制模式 rb 打开文件,并一次读取一个二进制兆字节(MiB,即 1,048,576 字节),而不是将整个文件加载到内存中。其赋值表达式语法需要 Python 3.8 或更高版本。

import hashlib
import sys

if len(sys.argv) != 2:
    raise SystemExit("Usage: python hash-file.py FILE")

digest = hashlib.sha256()
with open(sys.argv[1], "rb") as file:
    while chunk := file.read(1024 * 1024):
        digest.update(chunk)

print(digest.hexdigest())

在脚本的文件夹中,将实际文件的路径按如下方式传递。如果您的 Python 3 命令是 python3 或 py,请用该命令替换 python。

python hash-file.py "example.iso"

输出是一个64字符的十六进制SHA-256摘要。相同的字节会得到与PowerShell和其他工具相同的结果,但字母大小写可能不同。官方Python hashlib文档解释了update()和hexdigest()。在Windows上使用Python 3.12.14和PowerShell 7.6.5检查了小文件、空文件和多块文件,以确认结果一致。

当哈希值不匹配时需要检查的内容

  • 不同的发布文件:检查x64与ARM64、安装程序与压缩包,或不同版本。
  • 不同的算法:MD5、SHA-1和SHA-256会产生不同的摘要。请重新检查算法名称。
  • 未完成的下载:确认下载已完成,并且下载工具报告没有错误。
  • 提取或转换:压缩包的参考哈希不适用于从其中解压的文件。在编辑器中保存、转换换行符或重新压缩图像都会改变字节。
  • 路径或复制错误:检查命令实际读取的文件及整个参考值。避免使用被截断的摘要或从不同文件复制的摘要。

不要用自己计算的值替换无法解释的参考值以强制匹配。首先确认分发渠道和目标。如果重新下载仍有差异,请检查发布者的说明或该版本是否已被更正。

哈希可以做什么和不能做什么

用途 哈希的作用 附加要求
文件完整性 将当前文件内容与参考摘要进行比较。 参考源和算法必须是适当的。
重复检测 将哈希匹配的文件分组作为重复候选项。 考虑可能发生的碰撞;当必须确认内容完全相同时,还应逐字节比较。
数字签名 签名方案可以使用数据摘要。 仅计算哈希并不能创建签名或验证作者身份。
密码存储 密码验证也使用基于哈希的机制。 使用专门的密码存储方法,而不是简单的文件哈希 SHA-256。

哈希不是加密。加密的目的是为了使用适当的密钥恢复明文;而哈希不是用于重建其输入的格式。然而,短的或可预测的输入可以被猜测并其哈希进行比较,因此,仅进行哈希并不能保证数据保密。

对于密码,应选择可信的专用密码哈希方案实现,例如 Argon2id,并设置适当的计算成本和每个密码独有的盐值,而不要直接使用普通的 MD5、SHA-1 或 SHA-256。盐值是为每个密码设置的值,能够降低预计算猜测攻击的效果。OWASP 密码存储指南解释了密码存储和文件哈希为何需要不同的设计。对于下载校验,关键步骤是计算 SHA-256、获取可信的参考值,并比较完整的摘要。