Linux 如何使用 sha256sum 验证下载文件完整性
通过 sha256sum 命令计算哈希值并比对 SHA256SUMS 文件,确保下载文件未被篡改。本指南通过故意修改字节触发 FAILED 错误,带你深入理解校验和的工作原理与局限性,掌握验证文件完整性的标准操作流程。
在两分钟内通过校验和验证下载文件
要通过校验和验证下载文件,请对收到的文件进行哈希计算,并将该哈希值与发布者提供的哈希值进行比对。sha256sum 可以完成这两步工作:它既能独立输出摘要,也可以配合 -c 读取摘要列表并报告哪些文件匹配。本指南将引导你对一个自建文件执行完整流程,随后故意破坏该文件,以便你观察验证失败的过程,而非仅仅阅读理论。
请始终牢记一句话:校验和只能告诉你当前持有的字节是否与生成摘要时的字节一致,它无法证明这些字节的来源。验证来源需要数字签名和受信任的密钥。本指南的最后部分将明确界定这两者之间的界限。
创建练习文件
在临时目录中操作,确保不会影响系统其他部分。以下所有命令均来自 GNU coreutils,这是 Ubuntu 或 Debian 服务器上的基础命令集,无需安装任何软件。
mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txt你将得到一行输出:64 个十六进制字符,后跟两个空格,最后是文件名。这 64 个字符是文件的摘要。再次运行该命令,输出行完全相同,因为哈希计算是确定性的:相同的输入始终产生相同的输出。修改文件中的一个字符并再次运行,摘要不会发生微小的偏移。它看起来完全不同,因为输入位翻转一位会导致输出位约一半发生翻转。正是这一特性使得 64 字符的字符串可以作为 4 GB 镜像的有效替代标识。
保存 SHA256SUMS 文件并进行校验
屏幕上显示的摘要信息在一天后将毫无用处。请将其写入文件,格式应与 sha256sum 输出的格式一致,以便该工具后续能够读取。
sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMSsha256sum -c 会读取列表中的每一行,对该行指定的文件进行哈希计算,并将结果与记录的摘要进行比对。运行正常时,每个文件会输出一行结果:
payload.txt: OK同时请检查退出状态码,因为脚本通常只读取状态码而不解析文本。如果运行成功,echo $? 会输出 0。文件名 SHA256SUMS 是一种约定俗成的做法,而非强制规则;但由于各发行版和大多数发布页面均采用此命名,建议您也遵循此惯例,这样他人无需打开文件即可明确其用途。
修改一个字节并观察校验失败
现在故意破坏该文件。此操作在偏移量 5 处写入一个字节,且不改动其他内容,因此文件保持原有的长度和名称。
printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMSconv=notrunc 是关键标志:若不使用它,dd 会在写入停止处截断文件,这样你测试的将是一种更明显的损坏类型。此时校验输出如下:
payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchecho $? 会打印 1。FAILED 表示文件已被读取,但其摘要与列表中的不匹配。将原始字节恢复并确认校验结果回到 OK:
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMS这就是整个习惯。文件中任何位置的一个字节差异,都会产生 FAILED。因连接中断导致的下载不完整、镜像源提供了旧版本构建、代理在传输过程中重写了文件,或是磁盘返回了坏块:所有这些问题最终都会指向同一行输出。
当列表中包含您未下载的文件时
发行版提供的真实 SHA256SUMS 文件会列出该项目发布的所有镜像,而您只下载了其中一个。请在此处重现该情况。
printf 'a second file\n' > notes.txt
sha256sum payload.txt notes.txt > SHA256SUMS.all
rm notes.txt
sha256sum -c SHA256SUMS.allpayload.txt: OK
sha256sum: notes.txt: No such file or directory
notes.txt: FAILED open or read
sha256sum: WARNING: 1 listed file could not be readFAILED open or read 与 FAILED 是不同的故障,混淆两者会浪费时间。FAILED 表示字节内容错误。FAILED open or read 表示 sha256sum 根本没有获取到文件,因此未进行任何比对。在实际下载中,常见原因是工作目录不正确,因为列表中的文件名是相对于您运行命令所在位置的相对路径。请切换到存放文件的目录并重新运行命令。若只想检查您实际拥有的文件,请指定该文件:
sha256sum --ignore-missing -c SHA256SUMS.all该命令会打印 payload.txt: OK 并以退出码 0 结束。如果列表中没有任何名称对应的文件存在,--ignore-missing 不会静默地在零个文件上成功。它会报告 no file was verified 并以非零状态码退出,这正是您所期望的行为,因为如果检查未执行任何操作却显示通过,您将永远无法察觉到故障。
无需肉眼核对,直接粘贴已发布的摘要
肉眼对比 64 位十六进制字符极易出错。人们通常只检查开头和结尾的各 4 个字符就认定匹配,而这正是攻击者预料之中的漏洞。应交由工具进行比对。将 EXPECTED 设置为您从发布者处复制的摘要,使用 EXPECTED= 后跟粘贴的值,然后构建 -c 所需的单行格式:
printf '%s %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256摘要与文件名之间有两个空格,因此格式字符串中包含两个空格。这是 sha256sum 写入的格式,也是 -c 解析的格式。仅包含摘要而不含文件名的文件不是合法的校验和行,因此校验程序会因 no properly formatted checksum lines found 而拒绝整个文件,而不是猜测您的意图。部分项目发布的是 BSD 标记格式,即 SHA256 (payload.txt) = 后跟摘要。GNU coreutils 使用 sha256sum --tag payload.txt 写入该格式,并使用 -c 读取,因此保存为哪种格式均可。
当校验行为异常时,使用 cat -A SHA256SUMS 查看列表本身,它会用 $ 标记每一行的结尾,并显示不可见字符。如果行尾显示 ^M$,说明该文件是从 Windows 编辑器中引入了回车符。GNU sha256sum 会忽略该尾随字符并正常输出 OK,因此 CRLF 列表通常不会导致校验失败,但 coreutils 之外的工具对格式要求更为严格。请使用 tr -d '\r' < SHA256SUMS > SHA256SUMS.clean 对您保存的副本进行标准化处理。
校验和能证明什么,不能证明什么?
校验和仅能证明一件事:磁盘上的字节与发布摘要时所用的字节完全一致。这足以应对意外损坏。它也能应对粗心大意的攻击者,即对方替换了下载镜像站上的文件,但无法修改发布摘要的页面。
它无法证明作者身份。摘要是关于字节的事实,而非关于人的事实。如果同一个页面同时提供文件和摘要,那么任何能修改其中一个的人都能修改另一个,此时你的 OK 行仅代表镜像站与自身保持一致。因此,让校验和发挥作用的规则是:从不同于获取文件的来源处获取摘要。例如,通过 TLS (传输层安全) 从项目官网获取摘要,而从镜像站或种子文件获取镜像。这样攻击者必须同时控制两个位置才能得逞。
算法同样重要。截至 2026 年 8 月,SHA-256 (安全散列算法,256 位输出) 尚未发现碰撞,这也是发布者使用它的原因。MD5 (消息摘要 5) 和 SHA-1 已不再适用:自 2004 年起,人们就能构造出具有相同 MD5 摘要的两个不同文件;2020 年,针对 SHA-1 的选择前缀碰撞攻击也已被公开。MD5SUMS 文件仍可用于检测下载是否截断,因为随机损坏并非精心构造的碰撞。但它无法阻止蓄意欺骗。当项目同时发布两种校验和时,请务必使用 SHA-256。
签名接管验证流程
签名弥补了摘要留下的安全缺口。发布者使用私钥对摘要文件进行签名,用户则使用其公钥进行验证:gpg --verify SHA256SUMS.asc SHA256SUMS。如果验证通过,说明摘要列表确实来自持有该密钥的实体。随后,sha256sum -c SHA256SUMS 将磁盘上的文件与该列表关联,从而建立起从密钥到文件字节的完整信任链。
安全薄弱点随之转移到了密钥本身。如果从提供文件的同一页面获取密钥,攻击者可以同时控制这两部分。GnuPG 对此处理非常透明,首次验证时会打印 Good signature 以及 WARNING: This key is not certified with a trusted signature!。Good signature 仅代表数学运算通过,并不意味着该密钥确实属于你预期的项目。请从第二个来源获取指纹,例如不同域名下的项目文档,或已包含该密钥的发行版软件包,并对比完整的指纹而非仅最后 8 位字符。这与 SSH 私钥应受到的同等保护 出于相同原因:密钥是信任决策的核心,所有下游环节都继承自这一决策。
可复现构建将这一理念推向了更深层次。已发布的摘要仍将你绑定到由单台机器构建的二进制文件上。当项目的构建过程是可复现的,任何人都可以编译相同的源代码并获得字节完全一致的输出。因此,独立的构建者可以确认已发布的摘要,而无需仅凭单台服务器的声明。随着越来越多的代码通过自动化流水线和机器生成的补丁交付,这一点愈发重要。决定接受哪些内容进入构建属于策略问题,而 AI 辅助代码的开源策略 正是从另一端着手解决同样的供应链安全问题。
包管理器已为您完成此项工作
在 Debian 和 Ubuntu 上,apt 会在每次安装时自动执行此链式验证,无需额外干预。软件包索引中包含每个 .deb 文件的 SHA-256 摘要。Release 文件包含这些索引文件的摘要,而 InRelease 则包含对 Release 的签名,该签名会与 /usr/share/keyrings 和 /etc/apt/trusted.gpg.d 中的密钥进行比对。当验证链断裂时,apt 会给出提示:当缺少第三方仓库的密钥时显示 The following signatures couldn't be verified because the public key is not available: NO_PUBKEY;当获取的索引与已签名的 Hash Sum mismatch 不匹配时显示 Release,这通常意味着缓存代理提供了过期的文件,或者您在镜像站同步过程中进行了下载。
当某个项目主页要求您将 curl 的脚本直接通过管道传给 shell 执行时,请以此标准进行衡量。这种方式没有任何字节校验,且您无法查看脚本内容。服务器可以向脚本请求返回一套内容,而向浏览器请求返回另一套内容,且事后您无法获得副本进行检查。请使用 curl -fsSL <url> -o install.sh 将其下载为文件,计算哈希值,使用 less 阅读内容,确认无误后再运行。这个习惯只需花费约 20 秒,且非常值得在 全新 VPS 的前十分钟 内养成,即在服务器安装任何其他软件之前。
为手动安装的文件维护摘要列表
通过 apt 安装的软件包会被系统追踪。直接复制到 /usr/local/bin 的二进制文件则不在追踪范围内,系统也不会对其进行监控。通过摘要列表,你可以随时对这些文件进行校验:
printf 'a second file\n' > notes.txt
sha256sum *.txt > inventory.sha256
sha256sum -c --quiet inventory.sha256当所有文件匹配时,--quiet 不会输出任何内容;仅在校验失败时输出对应的行。因此,静默即代表通过,使用 echo $? 配合 0 可以验证这一点。这是在定时任务中使用的标准格式。--status 的输出更为精简,不显示任何信息,仅返回退出状态码。将相同的模式指向 sha256sum /usr/local/bin/* > ~/local-bin.sha256 对应的实际文件,即可建立基准。路径在列表中会按你输入的格式存储,因此使用绝对路径可以确保校验在任何目录下均可执行。
请明确该基准的局限性。它仅能检测文件是否被篡改。如果攻击者已经获取了 root 权限,该方法将失效,因为攻击者可以像修改二进制文件一样轻松地重写 inventory.sha256。若要确保校验结果的有效性,请将列表保存在本机之外。这涉及到一个更广泛的问题:你究竟信任 VPS 的哪一部分,以及还有谁能访问底层的磁盘数据。
FAQ
校验和匹配是否意味着下载是安全的?
不是。这仅意味着你拥有的字节与你比对的摘要一致。如果攻击者控制了发布摘要的页面,他们会发布他们自己文件的摘要,而你的校验结果会显示 OK。匹配仅代表一致性。安全性需要通过从不同来源获取的密钥来验证签名,只有这样,摘要才能继承该信任。
为什么 sha256sum -c 会输出 FAILED open or read?
因为它根本没有读取到该文件。其上方的一行会显示 No such file or directory 以及它所查找的文件名。SHA256SUMS 文件中的名称是相对于你运行命令所在目录的路径,因此请切换到存放下载文件的目录并再次运行。如果列表中还包含你未下载的文件,请添加 --ignore-missing。如果出现不带 open or read 的纯 FAILED,则情况相反:文件已被读取,但其摘要不匹配。
MD5 是否足以验证下载内容?
对于意外损坏,是的。传输中断或磁盘坏块不会偶然产生匹配的 MD5 摘要。但对于防范攻击者,则不够。自 2004 年起,人们就已经能构造出具有相同 MD5 摘要的两个不同文件,而 SHA-1 也在 2020 年被选择前缀碰撞攻击破解。当项目同时发布多种摘要时,请选择 SHA-256;如果项目仅提供 MD5,则说明其发布流程陈旧。
sha256sum -c 和 gpg --verify 有什么区别?
sha256sum -c 用于证明文件与摘要匹配。gpg --verify 用于证明摘要文件是由特定私钥的持有者签名的。它们回答的问题不同,因此当项目两者都提供时,请两者都运行。签名使摘要列表可信,而摘要列表随后使下载的文件可信。
如何根据网页上显示的摘要校验单个文件?
不要用肉眼比对字符。将摘要和文件名保存在同一行,中间用两个空格分隔,然后针对该文件运行 sha256sum -c,并查看它输出的 OK 或 FAILED。使用 printf '%s %s\n' 构建该行可以避免格式错误,否则 sha256sum 会因 no properly formatted checksum lines found 而拒绝该文件。