FlawOpen

flawopen.com/不安全的反序列化/Python pickle 安全

Python 的 pickle.load() 能安全加载不可信数据吗?

CWE-502:不可信数据反序列化参考页面
简要回答

不能。应把 pickle 当作包裹中的程序,而不是被动数据记录:加载时可能在应用验证对象前触发重建行为。跨越信任边界的数据应使用纯数据格式。

不安全 — 不可信字节在加载时可能触发代码
import pickle

# Never accept pickle bytes from a request, upload,
# shared cache, or other untrusted source.
obj = pickle.loads(untrusted_bytes)
更安全的默认方式 — 解析数据并验证结构
import json

def parse_profile(raw: bytes) -> dict[str, str]:
    if len(raw) > 65_536:
        raise ValueError("Payload too large")

    try:
        value = json.loads(raw)
    except (json.JSONDecodeError, UnicodeDecodeError):
        raise ValueError("Invalid JSON") from None

    if not isinstance(value, dict) or set(value) - {"display_name", "theme"}:
        raise ValueError("Invalid profile")

    name = value.get("display_name")
    theme = value.get("theme")
    if not isinstance(name, str) or len(name) > 80:
        raise ValueError("Invalid display name")
    if theme not in {"light", "dark"}:
        raise ValueError("Invalid theme")

    return {"display_name": name, "theme": theme}
Pickle 流:
Python 特有的字节序列,用于描述对象重建,包括全局对象引用和重建行为。
Unpickling:
解释数据流并重建对象图;过程中可能调用函数。
信任边界:
用户、服务、上传内容或共享存储能够控制或修改字节的位置。
CWE-502:
不可信数据反序列化;风险取决于攻击者能否提供或篡改应用加载的数据。
步骤 1

不可信字节进入 pickle 加载点

上传、请求、缓存或制品可能将攻击者控制或篡改的 pickle 数据带入进程。

步骤 2

Unpickler 解析全局对象

解释器处理重建指令;find_class() 可导入并返回命名的全局对象,包括函数。

步骤 3

加载过程触发行为

指令可在 load() 或 loads() 执行时调用函数,早于应用对结果的检查。

步骤 4

影响取决于进程权限

行为使用 Python 进程的权限。网络、秘密、文件访问和隔离决定影响范围。

为什么加载 pickle 会跨越代码执行边界

pickle 流可指定全局对象和重建函数。反序列化时,Unpickler.find_class() 解析全局对象(包括函数),操作码随后可触发重建。风险操作就是 pickle.load() 或 pickle.loads();无需后续单独调用 execute。执行行为继承进程权限。这是格式文档说明的行为;不要用 pickle 交换不可信数据。

JSON 能解决什么,不能解决什么

Python 文档警告,不可信或被篡改的 pickle 数据可能执行任意代码;JSON 解码本身不会产生这条任意代码执行路径。JSON 不会自动验证输入:限制大小,要求预期顶层类型和字段,按结构验证值,并单独执行授权检查。若旧系统暂时必须加载 pickle,应先用受保护密钥验证确切字节;签名仅在密钥假设成立时证明来源和完整性,不能让可信签署者提供的恶意数据变安全。应迁移到纯数据格式。

常见问题

限制 Unpickler 能让攻击者控制的 pickle 安全吗?

重写 find_class() 限制全局对象可以降低风险,但很难证明加载器对所有协议和可达行为都安全。不要把允许列表作为用户字节的默认防护;优先使用纯数据格式。

JSON 也需要验证吗?

需要。JSON 解码不会触发 pickle 式任意代码执行,但应用仍要检查类型、字段、大小、值和授权。应将 JSON 解析与业务规则分开。

主要参考资料

另请参阅 不安全反序列化:风险与修复 | flawopen.com Ruby YAML.load 安全吗?Psych 版本与 safe_load .NET BinaryFormatter:风险与迁移 Java ObjectInputStream 安全:降低反序列化风险 Newtonsoft.Json TypeNameHandling:安全配置? PHP unserialize() 与不可信数据