验证 PyPI Python 包的完整性
Posted
技术标签:
【中文标题】验证 PyPI Python 包的完整性【英文标题】:Verifying the integrity of PyPI Python packages 【发布时间】:2018-02-26 11:20:24 【问题描述】:最近有一些关于恶意库被上传到 Python 包索引 (PyPI) 的消息,请参阅:
-
Malicious libraries on PyPI
Malicious modules found into official Python repository(此链接包含恶意包列表)
Developers using malicious Python Modules
我不是试图转发这些新闻,而是试图阻止我自己和其他队友识别来自 PyPI 的包是否未被外部方更改。
问题:
-
从 PyPI 下载包后,我应该使用什么安全检查? MD5 或任何额外步骤?
MD5 签名是否足以验证 Python 包的完整性?
【问题讨论】:
抢注与哈希无关。您必须验证它是否是您正在使用的上游包。 另一个问题:一旦我下载了一个包并检查它没有任何域名仿冒,MD5签名是否足以检查这个包的完整性? pip 应该验证 MD5 签名,并且不容易(如果可能的话)碰撞它。编辑:新的 PyPI 前端 (pypi.io) 已迁移到 SHA256。 但是pip
不支持加密签名,所以这种方式是不可能的。
“另一个问题:一旦我下载了一个包并检查它没有任何域名仿冒,MD5签名是否足以检查这个包的完整性?”不,MD5 不是签名;这是一个哈希。这是一个不安全的哈希。
【参考方案1】:
首先,文章描述了typosquatting的危险,这是由于开发人员盲目地按名称安装包而没有检查它是否是正确的上游包。您可以通过访问作者的 GitHub 存储库并正确复制安装说明来避免这种情况。
除此之外,包裹可能会被篡改,但不太可能。由于 PyPI 文件是通过 HTTPS 传输的,因此从服务器获取哈希并验证它没有多大意义。 (如果作者的账号或者 PyPI 服务器被黑了,hash 不会阻止你安装恶意包。)
如果您需要额外的安全措施来防止服务器受损,请使用固定版本/哈希。详情请见document。
【讨论】:
【参考方案2】:首先,您担心使用pip
从PyPI
下载时获取恶意文件是有道理的。事实上,截至 2020 年,pip
has no way to cryptographically validate the authenticity and integrity 它下载的软件(但自 2013 年以来一直是 TODO 项)
其次,md5
可以验证文件的完整性,但不能安全地这样做。检查完整性也不够。为了安全验证从pip
下载的文件是您期望的文件,您必须:
-
通过确认文件实际上是由发布者生成(使用加密签名)来验证文件,并且
下载后验证文件的完整性
虽然pip
没有对此的内置支持,但您可以手动执行此操作,方法是手动从PyPI
下载所需文件及其分离的签名文件,然后使用gpg
检查签名。
例如,borgbackup
项目可以在 PyPI 的网站上查看:
点击“下载文件”按钮,您可以选择从以下 URL 下载最新的 tarball:
https://files.pythonhosted.org/packages/97/68/27d96a12f54894223ad6676ce4d215ad61771e3e723580f3ee6e609e17b7/borgbackup-1.1.13.tar.gz或者,您也可以使用 cURL 对 PyPI "simple" API 获取此 URL
user@disp5066:~$ curl -s https://pypi.org/simple/borgbackup/ | grep -i borgbackup-1.1.13.tar.gz
<a href="https://files.pythonhosted.org/packages/97/68/27d96a12f54894223ad6676ce4d215ad61771e3e723580f3ee6e609e17b7/borgbackup-1.1.13.tar.gz#sha256=164a8666a61071ce2fa6c60627c7646f12e3a8e74cd38f046be72f5ea91b3821">borgbackup-1.1.13.tar.gz</a><br/>
user@disp5066:~$
要获取此文件的签名,只需将.asc
附加到 URL:
user@disp5066:~$ wget https://files.pythonhosted.org/packages/97/68/27d96a12f54894223ad6676ce4d215ad61771e3e723580f3ee6e609e17b7/borgbackup-1.1.13.tar.gz.asc
--2020-07-02 07:51:12-- https://files.pythonhosted.org/packages/97/68/27d96a12f54894223ad6676ce4d215ad61771e3e723580f3ee6e609e17b7/borgbackup-1.1.13.tar.gz.asc
Resolving files.pythonhosted.org (files.pythonhosted.org)... 151.101.37.63, 2a04:4e42:9::319
Connecting to files.pythonhosted.org (files.pythonhosted.org)|151.101.37.63|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 862 [application/octet-stream]
Saving to: ‘borgbackup-1.1.13.tar.gz.asc’
borgbackup-1.1.13.t 100%[===================>] 862 --.-KB/s in 0s
2020-07-02 07:51:14 (37.2 MB/s) - ‘borgbackup-1.1.13.tar.gz.asc’ saved [862/862]
user@disp5066:~$ cat borgbackup-1.1.13.tar.gz.asc
-----BEGIN PGP SIGNATURE-----
iQJHBAABCgAxFiEEL4Gv+6sE4R/o7mXUJDrPqVH3jgEFAl7cGqwTHHR3QHdhbGRt
YW5uLWVkdi5kZQAKCRAkOs+pUfeOAd9ND/4nm2O7CK5a4aK41jAI1NisbgEtEJup
SiD6bvMKpo3VU0P/3Y6pUibKOGzaRImBTB04qS3LlgjB0mCp1RSVsj/Hn+yCNw+k
hfUH7E7JgAkq96Vkv1dcYgaJ9nhzuIAkEf0aDyzSo8HkBvGGN0/tfCQ7Nr7hI21u
v5qupIyu7KZrBwY389l7+6yJ9G5qCtHU0fDALRYyjsX+WphrAaizrhFZJO7Km8VZ
gZhAz3WUDPFwgNMb1mToUxpI2ZpnYnRxVBwjnX0Ps77ua4F5OsYM+hYwH5eX9bS9
gmb+W3NjUNjVVj4z+OgN8FGbCTeFVQ6E+IVdm55D4ZRU8KarvFoKOI7HS4GP/3iv
4iWqDaYBMRShnUTk1FKFCKjTb5tXewUGPwio+4bpgUyfJj0OWj1ecMqeF5VAslWz
6pZnsUqLpTFuHUA6dr18TKX4U+c6rdXVM7BhNZe2XtjaQwau6Wz9nC1xhZyFNl1q
CHY7jmLhsfP8GXkh31X9bJrKSZMyYRYat2e7kOroIJczRcHG9T708T+KzsfAb+6w
pWZbfWNfCbCmVQehyhDvNepB3IB5w6ijrZwKTamHAnYBVkAUD/aYwDQJf4nAL4YI
7JXBRpLlCVQGRUQdClqy8QjzpSZs5/Dbetvy5of753JbVjFQtGO2gLLp0wL0HB0v
vIZv3dfBDvfcXQ==
=F4gj
-----END PGP SIGNATURE-----
user@disp5066:~$
Pip 也无法将用于签名包的 gpg 密钥标记为“官方”密钥,因此您必须希望作者已在几个不同的域中发布了他们的密钥,以便您可以将其提取出来- 用一些方法来确认它是正确的,然后导入它并信任它。之后,您可以使用gpg
来验证从 PyPI 下载的文件的签名。
gpg --verify borgbackup-1.1.13.tar.gz.asc
另见:
-
https://github.com/borgbackup/borg/issues/4213
https://security.stackexchange.com/questions/232855/does-pythons-pip-provide-cryptographic-authentication-and-integrity-validation
【讨论】:
以上是关于验证 PyPI Python 包的完整性的主要内容,如果未能解决你的问题,请参考以下文章
win10 powershell 验证下载的包的MD5/sha1的签名值