如何防范Python exec执行用户代码时的命令注入风险?
安全执行用户提交的Python脚本方案
1. 限制exec的全局命名空间
直接使用exec的默认全局空间会暴露所有内置模块和函数,你可以手动构造一个仅包含必要允许项的全局字典,彻底切断用户代码对危险模块的访问路径:
# 仅保留业务验证需要的内置函数,比如len、str等 allowed_builtins = { 'len': len, 'str': str, 'int': int, # 按需添加,绝对不要包含__import__、eval这类危险函数 } # 构造干净的全局命名空间 safe_globals = { '__builtins__': allowed_builtins } user_script = """ # 用户提交的待验证代码 """ # 执行时仅传入自定义的安全全局空间 exec(user_script, safe_globals)
这种方式下,用户代码无法导入os、subprocess等模块,也不能调用__import__这类隐式导入方法,从根源上阻止命令注入。
2. 使用专业受限执行库
用RestrictedPython这类专门为受限场景设计的库,它会对用户代码做语法层面的拦截,禁止所有危险操作(比如导入模块、文件读写、系统调用),同时支持自定义允许的功能:
from RestrictedPython import compile_restricted from RestrictedPython.Eval import default_guarded_getitem from RestrictedPython.Guards import full_write_guard def run_safe_script(user_code): try: # 编译受限代码,自动拦截危险语法 compiled_code = compile_restricted(user_code, '<user_submitted>', 'exec') local_vars = {} # 配置仅允许的全局资源 safe_globals = { '__builtins__': None, '_getitem_': default_guarded_getitem, # 允许列表/字典索引操作 '_write_': full_write_guard, # 安全的赋值操作 # 按需添加业务需要的函数或变量 } exec(compiled_code, safe_globals, local_vars) return local_vars except Exception as e: return {"error": f"代码不符合规范:{str(e)}"}
RestrictedPython会处理很多绕过手段,比如通过字符串拼接调用__import__的情况,比手动构造全局空间更可靠。
3. 进程级隔离+资源限制
即使做了Python层面的限制,也可能存在语言本身的漏洞被利用,所以最好把用户代码放到独立进程中执行,同时设置严格的资源限制:
- 用
subprocess启动单独的Python进程,执行用户代码,加上-E(忽略环境变量)、-s(不加载用户site-packages)参数; - 限制进程的CPU时间、内存占用,防止恶意代码耗尽服务器资源;
- 执行完成后立即销毁进程,避免残留风险。
4. 前置代码静态扫描(辅助手段)
在执行前先对用户代码做静态分析,检查是否包含危险关键词(比如os.system、subprocess、__import__、eval等),但这种方法只能作为辅助,因为攻击者可以通过字符串混淆、动态生成代码绕过扫描,不能单独依赖。
注意事项
没有绝对安全的沙箱,最好的方案是多重防御结合:静态扫描过滤大部分明显危险代码 → RestrictedPython做语法层面拦截 → 独立进程隔离执行 → 资源限制防止滥用。
内容的提问来源于stack exchange,提问作者Lilian
相关产品推荐
相关产品推荐

