跳转到主内容
极星编程网:以代码为星,赴技术山海!

Python 调用系统命令的安全注意事项

应使用 subprocess.run() 替代 os.system() 和 os.popen(),传入参数列表而非拼接字符串,禁用 shell=True,显式控制 env 和 cwd,并警惕 SUID 二进制与环境变量劫持风险。 使用
subprocess.run()
替代
os.system()
和
os.popen()
os.system()
和
os.popen()
会直接将字符串交给 shell 解析,一旦参数含用户输入,极易触发命令注入。比如
os.system(f"ls {user_input}")
遇到
user_input = "; rm -rf /"
就会执行恶意命令。 正确做法是用
subprocess.run()
并传入参数列表(而非拼接字符串),让 Python 绕过 shell,直接调用程序:
subprocess.run(["ls", "-l", user_input]) # 安全:user_input 被当作文本参数,不会被 shell 解析
关键点: 始终用
list
形式传参,避免
shell=True
若必须用 shell 功能(如管道、通配符),则需严格过滤或转义用户输入,不推荐
subprocess.run(..., capture_output=True, text=True)
比
check_output()
更清晰可控 警惕
shell=True
的隐式风险 即使你没显式写
shell=True
,某些封装函数(如旧版
commands.getoutput()
,或第三方库的 exec 函数)内部可能默认启用 shell,导致参数被重新解析。 立即学习 “ Python免费学习笔记(深入) ”; 常见踩坑场景: 调用
subprocess.run("ls *.py", shell=True)
——
*
由 shell 展开,但若
*.py
来自用户,就等于放行任意文件名匹配逻辑 用
shlex.split()
处理用户输入再传给
subprocess
,却仍设
shell=True
,等于白做 在 Windows 上误以为
shell=False
就绝对安全,其实
cmd.exe
的某些内置命令(如
dir
)仍依赖 shell 行为 建议:除非明确需要 shell 特性(且已评估输入完全可信),否则一律禁用
shell=True
。 elasticsearch-9.4.0 win PHP中文网提供Elasticsearch 9.4.0 Windows 版本压缩包下载解压即用,内置 OpenJDK 无需额外配置 Java 环境。该版本重磅推出原生 Prometheus 支持、正式版 Elastic Workflows 以及基于 NVIDIA cuVS 的 GPU 加速向量索引,大幅提升 AI 检索与可观测性能力。建议前往官网下载,快速体验极速搜索与强大的数据分析功能。 下载 环境变量 与工作目录的污染风险 子进程会继承父进程的
os.environ
,其中可能含敏感信息(如
HOME
、
PATH
、
SSH_AUTH_SOCK
),或被恶意篡改影响命令行为。 实操建议: 显式传入干净的
env
参数,例如
env=dict(os.environ, PATH="/usr/bin:/bin")
用
cwd
明确指定工作目录,避免子进程在意外路径下读写文件 对敏感命令(如涉及密钥操作的
gpg
或
ssh
),考虑用
env={}
清空环境后按需注入必要变量 权限提升与进程逃逸的实际约束 Python 进程本身权限决定子进程上限:普通用户启动的脚本,无论怎么调用
subprocess
,都无法直接执行
sudo
或写入
/etc
——除非提前配置了免密 sudo 规则,而这属于系统层配置问题,不是 Python 能绕过的。 但仍有两类易被忽略的越权路径: 子进程调用的二进制本身有 SUID 位(如
/usr/bin/passwd
),此时它以文件所有者身份运行,可能提权 通过
LD_PRELOAD
或
pythonpath
等环境变量劫持子进程加载的库或模块,间接控制行为 所以不要只盯着“命令怎么拼”,还得看“谁在跑、在哪跑、带了什么环境”。尤其在容器或共享服务器中,这些边界比语法更关键。

相关文章