校验下载文件的正确姿势

68 阅读3分钟

对网络下载文件通常有两种校验手段:

  1. 用哈希算法计算文件摘要值,以校验文件的完整性(防篡改)。
  2. 用发布者的公钥对文件签名验签,以校验文件来源(防伪造)。

相关术语

  • PGP(Pretty Good Privacy):优良保密协议,最初指用来加密的商业软件的名字
  • OpenPGP:与最初 PGP 工具兼容的 IETF 开放标准,当前的"PGP"通常指此标准
  • GnuPG:是 OpenPGP 协议的一种完备的实现,此外还提供了完整的秘钥管理,和实现了许多协议中可选的加密、压缩算法
  • OpenSSL:用 C 实现 SSL/TLS 协议的个开源的加密函式库

完整性校验

哈希(Hash)是指将不定长度数据映射成固定长度的函数,通过它可以取到数据的摘要信息,常见的哈希算法有 SHA256MD5等;以 Linux/Ubuntu 为例,可在终端执行compgen -c | grep sum查看本机安装有哪些哈希工具(Windows下是Get-Filehashcertutil.exe -hashfile):

$ compgen -c | grep sum
sha1sum
sha256sum
md5sum
sha512sum
# ...

# 通常在文件下载页会有对应的哈希值,拷贝下来校验:
echo "0e2801e47fb1b92d2743204fcf650ce2fcad1a13ef7a44fe05738101a383e4a2 php-8.3.4.tar.gz" | sha256sum --check
# 校验通过时提示如下:
php-8.3.4.tar.gz: OK

签名校验

签名是指发送方用私钥对数据的摘要加签,接受方用发送方的公钥解签,并对用同样哈希算法取摘要值验证;发送方将自己的公钥发布到公钥服务器,接收方通过公钥指纹下载对应的公钥,再通过公钥和签名文件来验签,确保下载的文件是符合预期的。

# 先查看验签所需的密钥指纹(签名文件和目标文件放在同一目录下)
gpg --verify php-8.3.4.tar.gz.asc
# 输出:
gpg: assuming signed data in 'php-8.3.4.tar.gz'
gpg: Signature made Tue 12 Mar 2024 11:44:25 PM UTC
gpg:                using EDDSA key C28D937575603EB4ABB725861C0779DC5C0A9DE4
gpg: Can‘t check signature: No public key

# 1. 根据公钥指纹在公钥服务器上搜索公钥
gpg --search-keys 'C28D937575603EB4ABB725861C0779DC5C0A9DE4' 
# 输出:
gpg: data source: https://keys.openpgp.org:443
(1)	Jakub Zelenka <bukka@php.net>
	  256 bit EDDSA key 1C0779DC5C0A9DE4, created: 2021-04-10

# 2.1 通过KeyID将公钥导入到本地
gpg --receive-keys 1C0779DC5C0A9DE4
# 2.2 再用检查一下秘钥指纹确保下载下来的公钥是符合预期的(和官网提供值对比)
gpg --fingerprint 'C28D937575603EB4ABB725861C0779DC5C0A9DE4'

# 3. 验签
gpg --verify php-8.3.4.tar.gz.asc
# 校验通过时输出:
gpg: assuming signed data in 'php-8.3.4.tar.gz'
gpg: Signature made Tue 12 Mar 2024 11:44:25 PM UTC
gpg:                using EDDSA key C28D937575603EB4ABB725861C0779DC5C0A9DE4
gpg: Good signature from "Jakub Zelenka <bukka@php.net>" [full]