Python Web应用RCE漏洞主因是允许用户输入反序列化,修复关键为禁用危险入口:禁用pickle.loads、yaml.load(改safe_load)、json.loads的object_hook,升级库并全局扫描调用点。

Python Web应用中不当反序列化引发RCE,核心问题不在“怎么反序列化”,而在“谁允许你反序列化”——默认禁用pickle、yaml.load、json.loads的危险钩子,才是最直接有效的修复动作。
禁用pickle反序列化入口点
绝大多数Python RCE漏洞源于开发者显式或隐式调用了pickle.loads、pickle.load处理用户可控输入。它不校验类名、不隔离环境、不设沙箱,反序列化即执行任意代码。
- 检查所有
import pickle和pickle.loads(调用,尤其是API参数、Cookie、文件上传字段、缓存键值等位置 - 绝对不要用
pickle解析来自HTTP请求、数据库读取、消息队列的任意二进制数据 - 若必须跨进程传对象(如Celery任务),改用
json+ 显式白名单类构造,或启用Celery的task_serializer='json'配置 - 临时加固:在应用启动时插入
sys.modules['pickle'] = None(仅限确认无依赖场景)
替换yaml.load为yaml.safe_load
yaml.load默认使用FullLoader,可实例化任意Python类(如!!python/object:subprocess.Popen),是RCE高发区。很多框架(如旧版SaltStack、Ansible插件)曾因此沦陷。
- 全局搜索
yaml.load(,全部替换为yaml.safe_load( - 若需支持自定义标签,必须继承
yaml.SafeLoader并手动注册白名单构造器,禁止yaml.UnsafeLoader或yaml.CLoader直连用户输入 - 注意Django模板、Flask config.from_yaml等间接调用路径,它们可能封装了
yaml.load - PyYAML ≥ 5.1已将
yaml.load默认指向SafeLoader,但显式指定Loader=yaml.Loader仍会绕过
警惕json.loads的object_hook和object_pairs_hook
json本身安全,但开发者常通过object_hook回调自动实例化类(如json.loads(data, object_hook=MyModel))。一旦MyModel.__init__或属性赋值逻辑含命令执行(如调用os.system、eval),就构成RCE链。
立即学习“Python免费学习笔记(深入)”;
- 审查所有带
object_hook或object_pairs_hook参数的json.loads调用 - 避免在hook中调用不可信方法;若必须构造对象,改用
dataclasses.asdict或pydantic.BaseModel.parse_raw(配合strict=True) - 特别注意ORM模型反序列化(如SQLAlchemy
__init__中解析JSON字段)
升级+配置第三方库的反序列化行为
像msgpack、cloudpickle、dill等库也支持类加载,且默认行为宽松。修复不能只靠“不用”,还得看它们是否被间接引入。
-
msgpack.unpackb(data, strict_map_key=False):确保strict_map_key=True(防哈希碰撞DoS),禁用object_hook除非白名单明确 -
cloudpickle.load和dill.load:与pickle同级危险,禁止用于用户输入 - FastAPI/Starlette:检查
Body(..., media_type="application/json")是否被覆盖为自定义解析器,避免注入json.loadshook - 用
pip list --outdated确认PyYAML≥ 6.0、msgpack≥ 1.0.5,这些版本收紧了默认加载器策略
真正难防的不是某一行pickle.loads,而是那些藏在日志上报、监控埋点、配置热更新、甚至测试fixture里的反序列化调用——它们往往没有文档、不走主逻辑、测试覆盖率低。上线前用grep -r "pickle\|yaml\.load\|json\.loads.*hook" .扫一遍源码,比任何WAF规则都管用。


















