HOWTO · Python

Python 校验和

本教程介绍如何使用 Python 的 hashlib 生成文件校验和,并将其与可信的 SHA-256 摘要进行比较。

本页内容

文件校验和是根据文件字节计算出的紧凑摘要。下载文件后,你可以计算其摘要,并与通过可信渠道发布的摘要进行比较。两者匹配有助于发现意外更改或损坏,但这本身不能证明文件由谁创建:如果攻击者能同时替换文件和对应的摘要,就能让两者保持一致。

Python 的 hashlib 模块提供标准哈希算法。这个过程具有确定性:相同的字节和算法会产生相同的摘要,而哪怕只改变一个字节,结果通常也会变化。校验和描述的是字节,而不是文件名或文件格式。

文件校验和能说明什么

校验和可以帮助你检查文件副本是否仍包含预期内容。预期值必须来自你信任的来源,例如经过单独身份验证的发布页面。若从同一个不可信位置下载两个值再进行比较,几乎无法提供保障。对于安全相关的判断,应使用现代密码学哈希算法,例如 SHA-256,并单独验证参考值来源是否可信。

使用 hashlib 生成校验和

以二进制模式打开文件,这样 Python 就能对文件的原始字节进行哈希运算,不会解码文本或转换换行符。分块读取文件,并将每个数据块传给哈希对象的 update() 方法。这样即使文件远大于可用内存,内存用量也能保持有限。hexdigest() 返回可读的十六进制文本;digest() 则以打包后的字节形式返回相同摘要。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

import hashlib
from pathlib import Path
from tempfile import TemporaryDirectory


def sha256_file(path):
    digest = hashlib.sha256()
    with open(path, "rb") as file:
        for chunk in iter(lambda: file.read(64 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


with TemporaryDirectory() as directory:
    path = Path(directory) / "sample.bin"
    path.write_bytes(b"abc")
    expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
    actual = sha256_file(path)
    print(f"SHA-256: {actual}")
    print(f"Matches trusted value: {actual == expected}")
SHA-256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Matches trusted value: True

代码会创建一个小型示例文件,因此可以按原样运行;在自己的脚本中,将 path 替换为下载文件的路径。处理下载文件时,把 path 设为文件所在位置,并将生成的摘要与该文件的可信参考值进行比较。

将文件与可信校验和进行验证

独立保存或获取预期摘要,然后将它与 sha256_file 返回的值进行比较。示例中的布尔比较会在两个十六进制字符串相同时返回真。结果为假表示文件与该参考值不匹配;文件可能已损坏、被有意更改,或配错了参考值。请重新下载文件或调查来源,不要把不匹配当作某种特定原因的证明。

在安全敏感的工作流程中,只能依据发布者说明的格式规范化预期字符串,然后比较完整摘要。如果有完整摘要可用,不要只比较较短的前缀。比较成功只能证明文件与预期摘要所代表的可信字节相符;除非参考值本身经过身份验证,否则它不能验证发布者身份。

处理大文件和常见错误

分块读取可以避免将整个文件载入内存。只要每个字节都按顺序读取一次,所选块大小只会影响 I/O 效率,不会影响最终摘要。二进制模式很重要,因为文本模式可能会解码数据或转换换行符。像 with 语句所做的那样,只在读取期间保持文件打开。

对于很大的文件,避免一次用 file.read() 读取所有字节。还要确认路径指向你要验证的文件,并且计算参考值和本地计算时使用的是同一种哈希算法。即使文件内容没有变化,拼写不一致或算法不同也会产生不同字符串。如果文件在计算过程中发生变化,摘要可能反映其内容的混合状态;当其他进程可能正在写入文件时,应验证一份稳定的副本。

选择哈希算法并了解其局限

如果可信发布者提供了 SHA-256 参考值,可将 SHA-256 用于通用文件摘要。可以通过 hashlib.sha256() 使用该算法。某些旧示例和兼容性工作流程中仍会出现 MD5,但它容易受到碰撞攻击,不适合用于安全敏感的完整性检查。不要用 MD5 来确认来源真实性或防范蓄意攻击者。

校验和也不同于密码哈希:快速摘要适合比较文件,而密码需要使用专门设计并带盐的密码哈希方案。在所有情况下,摘要只能回答字节是否与某个参考值相符。参考值是否可信,取决于它如何获取以及如何保护。