跳到主要内容Python 开发环境安全:为何不应在下载目录直接运行脚本 | 极客日志Python
Python 开发环境安全:为何不应在下载目录直接运行脚本
本文深入分析了在 Python 开发过程中直接在下载目录运行脚本的安全隐患,揭示了 sys.path 机制、PYTHONPATH 环境变量及当前目录优先级带来的潜在风险。文章详细阐述了恶意脚本如何通过覆盖系统模块(如 pip.py)或利用空字符串路径解析进行攻击,并提供了全面的防护方案。建议包括严格使用虚拟环境隔离依赖、避免在当前工作目录执行脚本、正确配置环境变量、禁用不安全的 PYTHONPATH 设置、定期审计依赖包以及配置可信源等措施,以确保开发环境的安全性。
Python 已经成为全球最受欢迎的编程语言之一。其简明易用的脚本语法,只需将一段程序放入.py 文件中,就能快速运行,极大地降低了编程门槛。
而且 Python 语言很容易上手模块管理。比如你编写了一个模块 my_lib.py,只需在调用这个模块的程序中加入一行 import my_lib 即可。这种设计的好处是,初学者能够非常方便地执行命令和测试代码。但是对攻击者来说,这等于是为恶意程序大开后门。
尤其是一些初学者将网上的 Python 软件包、代码下载到本地 ~/Downloads 文件夹后,就直接在此路径下运行 python 命令,这样做会给电脑带来极大的安全隐患。本文旨在深入剖析这些风险背后的技术原理,并提供一套完整的加固方案。
为什么这样做会有危险?
首先,我们要了解 Python 程序安全运行需要满足的三个核心条件:
- 系统路径上的每个条目都处于安全的位置;
- '主脚本'所在的目录始终位于系统路径中;
- 若 python 命令使用-c 和-m 选项,调用程序的目录也必须是安全的。
如果你运行的是正确安装的 Python,那么 Python 安装目录和 virtualenv 之外唯一会自动添加到系统路径的位置,就是当前主程序的安装目录。这就是安全隐患的主要来源。
如果你把 pip 安装在/usr/bin 文件夹下,并运行 pip 命令。由于/usr/bin 是系统路径,因此这是一个非常安全的地方。但是,有些人并不喜欢直接使用 pip,而是更喜欢调用/path/to/python -m pip。这样做的好处是可以避免环境变量$PATH 设置的复杂性,而且对于 Windows 用户来说,也可以避免处理安装各种 exe 脚本和文档。
所以问题就来了,如果你的下载文件中有一个叫做 pip.py 的文件,那么你将它将取代系统自带的 pip,接管你的程序。
下载文件夹并不安全
比如你不是从 PyPI,而是直接从网上直接下载了一个 Python wheel 文件。你很自然地输入以下命令来安装它:
~$ cd Downloads
~/Downloads$ python -m pip install ./totally-legit-package.whl
这似乎是一件很合理的事情。但你不知道的是,这么操作很有可能访问带有 XSS JavaScript 的站点,并将带有恶意软件的 pip.py 到下载文件夹中。
~$ mkdir attacker_dir
~$ cd attacker_dir
~/attacker_dir$ echo 'print("lol ur pwnt")' > pip.py
~/attacker_dir$ python -m pip install requests
lol ur pwnt
看到了吗?这段代码生成了一个 pip.py,并且代替系统的 pip 接管了程序。当你在该目录下运行任何涉及 pip 的操作时,恶意脚本都会优先被执行。
设置$PYTHONPATH 也不安全
前面已经说过,Python 只会调用系统路径、virtualenv 虚拟环境路径以及当前主程序路径。
你也许会说,那我手动设置一下 $PYTHONPATH 环境变量,不把当前目录放在环境变量里,这样不就安全了吗?
非也!不幸的是,你可能会遭遇另一种攻击方式。下面让我们模拟一个'脆弱的'Python 程序:
try:
import optional_extra
except ImportError:
print("extra not found, that's fine")
然后创建 2 个目录:install_dir 和 attacker_dir。将上面的程序放在 install_dir 中。然后 cd attacker_dir 将复杂的恶意软件放在这里,并把它的名字改成 tool.py 调用的 optional_extra 模块:
~/attacker_dir$ python ../install_dir/tool.py
extra not found, that's fine
但是这个习惯用法有一个严重的缺陷:第一次调用它时,如果$PYTHONPATH 以前是空的或者未设置,那么它会包含一个空字符串,该字符串被解析为当前目录。
~/attacker_dir$ export PYTHONPATH="/a/perfectly/safe/place:$PYTHONPATH";
~/attacker_dir$ python ../install_dir/tool.py
lol ur pwnt
为了安全起见,你可能会认为,清空$PYTHONPATH 总该没问题了吧?
~/attacker_dir$ export PYTHONPATH="";
~/attacker_dir$ python ../install_dir/tool.py
lol ur pwnt
这里发生的事情是,$PYTHONPATH 变成空的了,这和 unset 是不一样的。
因为在 Python 里,os.environ.get("PYTHONPATH") == ""和 os.environ.get("PYTHONPATH") == None 是不一样的。
如果要确保$PYTHONPATH 已从 shell 中清除,则需要使用 unset 命令处理一遍,然后就正常了。
设置 PYTHONPATH 曾经是设置 Python 开发环境的最常用方法。但你以后最好别再用它了,virtualenv 可以更好地满足开发者需求。如果你过去设置了一个 PYTHONPATH,现在是很好的机会,把它删除了吧。
如果你确实需要在 shell 中使用 PYTHONPATH,请用以下方法:
export PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}new_entry_1"
export PYTHONPATH="${PYTHONPATH:+${PYTHONPATH}:}new_entry_2"
在 bash 和 zsh 中,$PYTHONPATH 变量的值会变成:
$ echo "${PYTHONPATH}"
new_entry_1:new_entry_2
如此便保证了环境变量$PYTHONPATH 中没有空格和多余的冒号。
如果你仍在使用$PYTHONPATH,请确保始终使用绝对路径!
另外,在下载文件夹中直接运行 Jupyter Notebook 也是一样危险的,比如 jupyter notebook ~/Downloads/anything.ipynb 也有可能将恶意程序引入到代码中。
预防措施与最佳实践
1. 规范 Pip 的使用方式
如果要在下载文件夹~/Downloads 中使用 Python 编写的工具,请养成良好习惯,使用 pip 所在路径/path/to/venv/bin/pip,而不是输入/path/to/venv/bin/python -m pip。虽然两者功能相似,但前者能更好地隔离环境依赖。
2. 避免将~/Downloads 作为当前工作目录
避免将~/Downloads 作为当前工作目录,并在启动之前将要使用的任何软件移至更合适的位置。例如,创建一个~/projects 或~/code 目录专门存放开发代码,保持下载目录仅用于临时存储。
3. 使用虚拟环境隔离依赖
强烈建议使用 venv 或 virtualenv 创建独立的虚拟环境。这样可以确保项目依赖不会污染全局环境,同时也能在一定程度上隔离路径搜索风险。
python3 -m venv my_project_env
source my_project_env/bin/activate
pip install requests
激活环境后,所有的 pip 安装和 python 运行都将在该隔离环境中进行,sys.path 将不再包含当前工作目录以外的无关路径。
4. 配置 Pip 安全策略
你可以配置 pip.conf 文件来限制 pip 的行为。在 ~/.config/pip/pip.conf (Linux/Mac) 或 %APPDATA%\pip\pip.ini (Windows) 中添加以下内容:
[global]
trusted-host = pypi.org
index-url = https://pypi.org/simple
5. 检查 sys.path 内容
在运行关键脚本前,可以在脚本开头打印 sys.path 的内容,确认没有意外的路径被加入。
import sys
for path in sys.path:
print(path)
如果发现当前目录(通常显示为 '')出现在列表中且并非预期行为,则说明存在安全风险。
6. 警惕 sitecustomize.py
Python 解释器在启动时会加载 sitecustomize.py 和 usercustomize.py 文件。如果这些文件存在于 sys.path 中的某个位置,它们会在标准库导入之前执行。攻击者可能利用这一点注入恶意代码。定期检查这些文件是否存在于你的系统中,并确保它们未被篡改。
7. CI/CD 环境下的安全
在持续集成/持续部署环境中,同样需要注意路径安全问题。构建脚本应明确指定虚拟环境路径,避免隐式依赖当前工作目录。使用 Docker 容器化部署可以进一步隔离环境,减少主机系统被渗透的风险。
8. 定期审计依赖
使用如 safety 或 pip-audit 等工具定期扫描已安装的包,检查是否存在已知漏洞。
pip install safety
safety check
总结
了解 Python 从何处获取执行代码非常重要。赋予其他人执行任意 Python 命令的能力等同于赋予他对你电脑的完全控制权!
通过遵循上述最佳实践,包括使用虚拟环境、避免在公共目录运行脚本、正确配置环境变量以及定期审计依赖,你可以显著降低 Python 开发过程中的安全风险。安全不仅仅是防火墙和杀毒软件的事,良好的编码习惯和环境配置同样是防御体系的重要组成部分。
相关免费在线工具
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online