●
CWE-502 / Unsafe Deserialization
不安全反序列化:风险与修复
不可信的 pickle、Java 序列化和 PHP unserialize 数据如何触发危险行为,以及如何替换或限制它们。
💡 通俗解释 (ELI5)
序列化就像邮寄模型的组装说明;反序列化会按说明重建数据。某些格式在重建时还会指定类或调用 hook。接受不可信说明可能触发接收方未预期的行为。具体影响取决于格式、运行时、可用类和应用环境。
Core Concepts & Key Terms
- 序列化 / 反序列化
- 将数据或对象转换为存储或传输表示,再由程序解析或重建。
- 反序列化 hook
- Python __reduce__、Java readObject、PHP __wakeup / __unserialize 等回调,可能在对象重建时运行。
- Gadget chain
- 利用程序中已有库行为串联出非预期效果的调用链。是否可用取决于应用和库版本。
- 反序列化过滤器
- 读取对象流时限制类或对象图指标的策略。它能降低风险,但不代表应优先接受不可信原生对象流。
How Unsafe Deserialization Can Become an Exploit Chain
Step 1
不可信字节到达解码器
Cookie、API 请求体、队列消息或存储记录包含攻击者可以影响的数据。
Step 2
应用调用原生对象格式
代码将字节交给 Python pickle、Java ObjectInputStream 或 PHP unserialize() 等解码器。
Step 3
重建过程触发格式相关行为
根据格式和可访问类,构造器、hook、autoload 或库方法可能在应用层验证前运行。
Step 4
影响取决于可达行为
可用的 gadget 或 hook 可能导致未授权影响;其他输入可能仅失败或消耗资源。并非每种格式或应用都会自动执行代码。
Python / Flask: Unsafe Object Loading vs. Primitive JSON Validation
不安全模式
# VULNERABLE: pickle can execute behavior during unpickling.
from flask import Flask, request
import pickle
app = Flask(__name__)
@app.post("/api/session")
def load_session():
# Never deserialize attacker-controlled bytes with pickle.
session = pickle.loads(request.get_data())
return {"user_id": session.user_id}
更安全的验证
# SAFER: parse JSON primitives, then validate expected shape.
from flask import Flask, abort, request
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024
@app.post("/api/session")
def load_session():
payload = request.get_json()
if not isinstance(payload, dict):
abort(400, "Expected a JSON object")
user_id = payload.get("user_id")
if type(user_id) is not int or user_id <= 0:
abort(400, "Invalid user_id")
# Resolve authorization and session state server-side.
return {"user_id": user_id}
工程加固检查清单
JSON 输入仍需设置大小限制并验证数据结构。对于旧式对象格式,不要只依赖类允许列表:应在反序列化前验证序列化字节本身的真实性,并保护密钥。MAC 不会加密数据,也不能阻止重放。
- 不要用 Python pickle 或 PHP unserialize() 反序列化不可信原生对象流;优先使用 JSON 等原始数据格式并校验 schema 和大小。
- 暂时无法移除 Java 序列化时,配置 ObjectInputFilter allowlist 和对象图限制;该过滤器并非所有部署默认启用。
- 遗留数据需要完整性保护时,在反序列化前用妥善管理的 MAC 密钥验证原始字节;MAC 不加密,也不防重放。
- 将会话权限保留在服务器端,或使用受维护的框架签名令牌并配置过期时间、受众和密钥轮换。