本文目录导读:

- 核心原则:信任边界 + 最小权限
- 案例一:运行不可信的第三方库(依赖安全)
- 案例二:执行用户输入的代码(最危险场景)
- 案例三:处理用户请求/Web服务(网络与数据安全)
- 案例四:运行在线学安全(Jupyter Notebook等)
- 案例五:云端/容器部署(运行时沙箱与资源隔离)
- 一份快速自查清单
对于Python运行安全,没有“万能钥匙”,而是需要根据不同的运行场景(是运行自己的脚本、运行别人的代码、还是部署给用户用的Web服务)采取不同的防御策略。
下面我把常见的Python运行安全案例,按照风险等级从低到高,以及对应的保障方法整理出来。
核心原则:信任边界 + 最小权限
- 信任边界:明确哪些代码是可信的(你自己写的),哪些是不可信的(用户输入、第三方库、外部文件)。
- 最小权限:程序运行时,只给它完成工作所需的最小权限(不需要写文件就不要给写权限,不需要网络就不要给网络)。
运行不可信的第三方库(依赖安全)
风险:恶意Python包可能窃取环境变量、SSH密钥,或者植入挖矿脚本。
保障方法:
- 使用虚拟环境(隔离依赖):
- 每个项目使用独立的虚拟环境(
venv,virtualenv,conda)。 - 千万不要用
sudo pip install全局安装。
- 每个项目使用独立的虚拟环境(
- 依赖锁定与哈希校验:
- 生成
requirements.txt或poetry.lock文件,锁定所有依赖的精确版本和哈希值。 - 安装时启用哈希检查:
pip install --require-hashes -r requirements.txt。
- 生成
- 安全扫描:
- 使用工具(如
pip-audit,safety,Dependabot)定期扫描依赖中的已知漏洞(CVE)。
- 使用工具(如
- 来源限制:
- 只从官方 PyPI 或私有可信源下载,使用
--index-url限制来源,避免从 PyPI 镜像(非官方)下载到木马包。
- 只从官方 PyPI 或私有可信源下载,使用
执行用户输入的代码(最危险场景)
风险:用户通过 eval(), exec(), os.system() 传入恶意命令,如 os.system("rm -rf /")。
保障方法:
- 绝对原则:永远不要直接
eval()或exec()用户输入。 - 替代方案:
- 用
ast.literal_eval()替代eval(),它只解析字面量(字符串、数字、元组、列表、字典),不会执行任何代码。 - 如果需要执行数学公式,用
numexpr或simpleeval库,它们提供沙箱环境。
- 用
- 沙箱运行(万不得已时):
- Docker 容器:在隔离容器内执行用户代码,限制CPU、内存、网络和文件系统。
subprocess+ 超时:在子进程中运行代码,并设置严格的timeout,防止无限循环。- PyPy沙箱(已不再维护,仅作参考):曾提供文件系统和网络访问控制。
示例(危险):
user_code = "os.system('rm -rf /')"
eval(user_code) # 危险!
示例(安全):
import ast
user_input = "{'name': 'alice', 'age': 25}"
data = ast.literal_eval(user_input) # 安全,只解析字典
处理用户请求/Web服务(网络与数据安全)
风险:SQL注入、命令注入、跨站攻击、目录穿越。
保障方法:
- 参数化查询/ORM:
- 永远不要拼接SQL字符串,使用SQLAlchemy等ORM或参数化查询(
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)))。
- 永远不要拼接SQL字符串,使用SQLAlchemy等ORM或参数化查询(
- 输入验证:
- 使用
pydantic或marshmallow定义严格的输入模型,校验类型、长度、正则表达式。
- 使用
- 路径安全:
- 处理文件名或路径时,使用
os.path.basename()仅提取文件名,然后使用os.path.join()在安全的目录下构造绝对路径,防止../../etc/passwd的目录穿越攻击。
- 处理文件名或路径时,使用
- 低权限运行:
- 永远不要用
root用户运行Web服务,创建一个专用系统用户webapp,使其对项目目录只有读和执行权限(对某些目录可能有写权限),对日志目录有写权限。
- 永远不要用
运行在线学安全(Jupyter Notebook等)
风险:交互式环境允许直接执行任意系统命令。
保障方法:
- Jupyter有安全措施:Jupyter会自动生成并校验token,防止未授权访问,不要随意关闭或公开token。
- 清理输出:在分享Notebook前,清除所有包含敏感信息(密码、API密钥、路径)的单元格输出。
- 扩展审计:使用
nbsafety或jupyterlab-kite等扩展,可以自动分析变量依赖和执行顺序,减少误操作风险。
云端/容器部署(运行时沙箱与资源隔离)
风险:单一程序泄露或崩溃影响整个服务器。
保障方法:
- 容器化:Docker/Kubernetes 隔离是关键。
- 能力限制:
- 在Docker中,使用
--cap-drop=ALL删除所有默认能力(capability),然后按需添加。 - 使用只读文件系统
--read-only。
- 在Docker中,使用
- 资源限制:
- Docker 的
--memory,--cpus限制资源使用,防止 DoS 攻击(如无限循环导致系统崩溃)。
- Docker 的
- seccomp/AppArmor:使用安全模块进一步限制系统调用。
一份快速自查清单
当你部署一个Python程序时,可以对照检查:
- 依赖安全:
requirements.txt哈希校验了吗?虚拟环境隔离了吗?有无已知CVE? - 代码执行:有没有
eval()exec()?有没有os.system()subprocess.Popen(shell=True)?- 如果有,能否替换为
ast.literal_eval()或沙箱(Docker)?
- 如果有,能否替换为
- 用户输入:SQL参数化了吗?路径被用户控制了吗?(警惕 )
- 权限控制:运行时用户是
root吗?文件系统权限是否最小化? - 秘密管理:密码、密钥是否硬编码在代码里?
- 不要硬编码!应使用环境变量或秘密管理服务(如Vault, 云服务商Secrets Manager)。
一句话总结:Python运行安全的核心不是语言本身,而是“假设所有外部输入都是恶意的,并以此为基础来设计和运行它”。