本文目录导读:

不安全,绝不应用于不受信任的数据或反序列化场景。
Pickle 存在的核心安全问题在于:它不是一个只存数据的格式,而是一个基于栈的虚拟机协议,反序列化时,Pickle 会重新执行构建对象的字节码指令,这意味着攻击者可以构造恶意的 Pickle 数据,在反序列化过程中执行任意 Python 代码。
为什么危险?
Pickle 序列化的不是数据,而是“如何重建对象”的指令,一个经典的攻击载荷如下:
import pickle
import os
# 攻击者构造的恶意 pickle 数据
class Evil:
def __reduce__(self):
return (os.system, ('echo 你被入侵了',))
pickle_data = pickle.dumps(Evil())
# 反序列化时,会执行 os.system('echo 你被入侵了')
pickle.loads(pickle_data) # 危险!
只要 pickle.loads 被调用,这段代码就会执行,攻击者可以换成 rm -rf / 或其他破坏性命令。
安全使用场景
- ✅ 可信环境内部:如进程间通信、临时缓存(且双方代码可控)
- ✅ 短期存储:自己生成的 pickle,只由自己读取
- ✅ 签名验证:先对 pickle 数据做 HMAC 签名,反序列化前校验完整性
不安全场景
- ❌ 客户端上传的数据:如 Web 应用的 session 存储
- ❌ 来自网络的未验证数据:如 API 接收的二进制流
- ❌ 用户输入的文件:如让用户上传 .pkl 文件加载
更好的替代方案
| 需求 | 推荐方案 | 原因 |
|---|---|---|
| 安全数据交换 | JSON (+ schema验证) | 纯数据,不执行代码 |
| 复杂Python对象 | MessagePack 或 cloudpickle (仅可信环境) | 相比pickle更可控 |
| 高性能 | Protocol Buffers 或 Apache Arrow | 跨语言,类型安全 |
| 配置文件 | YAML (用 safe_load) | 避免任意代码执行 |
如果必须用 Pickle 且不信任来源
import pickle
import hmac
import hashlib
# 写入时签名
secret_key = b'your-secret-key'
data = pickle.dumps(obj)
signature = hmac.new(secret_key, data, hashlib.sha256).digest()
# 存储 signature + data
# 读取时验证签名
stored_sig = data[:32]
stored_data = data[32:]
expected_sig = hmac.new(secret_key, stored_data, hashlib.sha256).digest()
if hmac.compare_digest(stored_sig, expected_sig):
obj = pickle.loads(stored_data)
| 维度 | |
|---|---|
| 是否安全 | 🚫 不安全 |
| 能否用于用户输入 | 绝对不能 |
| 内部使用 | 可以,但要谨慎 |
| 最佳实践 | 尽量用 JSON/jsonlines/Avro/Parquet |
记住这条黄金法则:永远不要对不可信的数据调用 pickle.loads()。