FlawOpen
● 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 不会加密数据,也不能阻止重放。

← 浏览完整安全目录 查看漏洞实战指南 →