Python Pickle 序列化为什么存在严重安全隐患?

来源:Golang编程网作者:清原小日向头衔:网络博主
导读:本期聚焦于小伙伴创作的《Python Pickle 序列化为什么存在严重安全隐患?》,敬请观看详情。把不可信来源的数据直接交给 pickle.loads 反序列化,相当于允许对方在你机器上执行任意代码。Pickle 的协议在设计上会记录对象重建指令,解释器加载时会调用对象的 __reduce__ 方法返回可执行单元。一旦攻击者构造了恶意 payload,就能借反序列化过程触发系统命令执行或文件读写。相比之下,JSON 仅表达数据结构,不具备执行能力。因此在跨网络、跨信任边界传递数据时,应避免使用 Pickle,或配合签名校验与白名单机制降低风险。

Python 标准库中的 pickle 模块提供了对象序列化与反序列化能力,可以将内存中的对象转换为字节流,也能将字节流还原为对象。这种机制在缓存、进程间通信和模型持久化等场景中非常方便,但其底层设计决定了它并不适合处理任何不可信的数据。

Python Pickle 序列化为什么存在严重安全隐患?

Pickle 的执行模型本质

pickle 并不是单纯的数据格式,而是一套“对象重建指令集”。在序列化时,pickle 会记录对象的类型、状态以及重建该对象所需调用的函数或方法。最核心的环节是对象可以通过定义 __reduce__ 方法,返回一个元组,其中第一个元素是可调用对象,第二个元素是传给它的参数。反序列化时,pickle 会真的去调用这个可调用对象。

这意味着,如果攻击者能够控制被反序列化的字节流,他就可以构造一个对象,使其 __reduce__ 返回 os.system 这样的危险函数以及对应参数。当受害者执行 pickle.loads 时,系统命令就会直接被执行。下面的代码展示了恶意 payload 的构造方式:

import pickle
import os

class Evil:
    def __reduce__(self):
        return (os.system, ('echo hacked > /tmp/pwned.txt',))

payload = pickle.dumps(Evil())
# 受害者侧执行以下代码即中招
pickle.loads(payload)

上述代码中,Evil 类的 __reduce__ 告诉 pickle:重建时请调用 os.system 并传入字符串参数。反序列化过程没有沙箱限制,因此命令会被原样执行。这种机制与 JSON 等纯数据交换格式有本质区别。

常见触发场景与危害

在实际工程中,Pickle 安全隐患常出现在多处。其一是使用 pickle 作为 Web 应用的会话存储格式,并将 cookie 或请求体中的内容直接反序列化;其二是从公网下载所谓的“模型文件”并用 pickle 加载,例如某些机器学习社区分享的 pt 或 pkl 文件;其三是多进程任务队列(如早期 Celery 配置)使用 pickle 序列化任务参数,且消息中间件未做鉴权。

一旦被利用,攻击者能做到的事情远超读取数据。他可以执行任意系统命令、读取服务器上的密钥文件、反弹 shell、甚至进一步横向移动。由于反序列化发生在业务代码之前,传统 WAF 或参数校验往往难以拦截这种攻击。下面是一段存在风险的 Flask 伪代码:

from flask import Flask, request
import pickle

app = Flask(__name__)

@app.route('/load')
def load():
    data = request.args.get('data')
    # 危险:直接反序列化用户传入的字节
    obj = pickle.loads(bytes.fromhex(data))
    return str(obj)

该接口把用户传入的十六进制字符串还原为字节后交给 pickle.loads,攻击者只需生成恶意 payload 的十六进制即可远程控制服务器。这类接口在上线前若未做安全评审,极易成为入侵入口。

安全替代与防护方案

如果需求只是传递数据结构而非复杂对象,优先使用 json 模块。JSON 只能表示字典、列表、字符串等基础类型,不具备代码执行能力。对于必须序列化自定义类的场景,可考虑 dataclasses 加 JSON 编码,或使用 marshaljsonpickle 等受控方案,并严格限制类型。

当确实需要使用 pickle 时,应做到以下几点:仅反序列化来自可信通道且经过签名的数据;使用 HMAC 校验字节流完整性,防止被篡改;在加载前通过白名单限制可接受的类。下面示例展示了带签名校验的加载方式:

import pickle
import hmac
import hashlib

SECRET = b'my-secret-key'

def safe_loads(data, sig):
    expect = hmac.new(SECRET, data, hashlib.sha256).digest()
    if not hmac.compare_digest(expect, sig):
        raise ValueError('签名校验失败')
    return pickle.loads(data)

# 使用方先生成签名再传输
raw = pickle.dumps({'a': 1})
sig = hmac.new(SECRET, raw, hashlib.sha256).digest()
obj = safe_loads(raw, sig)

即便如此,签名只能防止数据被篡改,不能阻止拥有密钥的一方自己构造恶意对象。因此最根本的原则仍是:不要对不可信数据使用 pickle。在跨系统、跨信任边界的通信中,选择语言无关且表达能力受限的序列化协议,如 JSON、MessagePack 或 Protocol Buffers,才是更稳健的做法。

总结

Pickle 的安全隐患来源于其“可执行的反序列化”本质,而非实现缺陷。开发者在享受其便利的同时,必须清楚区分信任边界。对内临时缓存和对外部输入处理应采用完全不同的技术选型,避免将强大的对象重建能力暴露给潜在攻击者。

Python Pickle 反序列化漏洞修改时间:2026-08-09 05:21:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。