当前位置: 首页 > 新闻动态 > 网络资讯

Python 对象序列化与反序列化原理

作者:冰川箭仙 浏览: 发布日期:2026-01-31
[导读]:pickle反序列化会执行任意代码,因其本质是记录并重放对象重建的构造指令流,攻击者可通过控制输入注入__reduce__恶意调用;它本就只应限于可信环境使用。
pickle反序列化会执行任意代码,因其本质是记录并重放对象重建的构造指令流,攻击者可通过控制输入注入__reduce__恶意调用;它本就只应限于可信环境使用。

为什么 pickle 反序列化会执行任意代码

pickle 不是数据格式协议,而是一套 Python 对象的“运行时快照”机制。它序列化时记录的是对象类型、属性值、以及重建该对象所需的**构造指令流**(类似字节码),反序列化时直接在当前解释器中执行这些指令。

这意味着只要攻击者能控制输入字节流,就能注入 __reduce__ 方法返回恶意函数调用,比如 os.systemeval。这不是 bug,而是设计使然——pickle 本就只应在可信环境中使用。

  • 永远不要用 pickle.load() 解析来自网络、文件或用户输入的未知数据
  • 替代方案:用 json(仅支持基础类型)、dataclasses.asdict() + json、或 msgpack(需显式注册类)
  • 若必须用 pickle,可用自定义 Unpickler 重写 find_class,白名

    单限制可加载的模块和类

json 序列化失败常见原因与绕过方式

json.dumps() 默认只接受 strintfloatboolNonelistdict 这七种类型。遇到 datetimebytes、自定义类实例时直接报 TypeError: Object of type ... is not JSON serializable

解决核心思路是提前把非标量对象“降维”成 JSON 可表示的结构:

  • default 参数传入转换函数,例如处理 datetimelambda obj: obj.isoformat() if isinstance(obj, datetime) else None
  • bytes,先 obj.decode('utf-8')(确保是文本)或 base64.b64encode(obj).decode('ascii')
  • 避免重写 JSONEncoder 子类——除非需要复用或统一规则;临时场景用 default 更轻量
  • 注意:json 不保留类型信息,反序列化后得靠业务逻辑手动还原为 datetime 等对象

自定义类如何支持 __getstate____setstate__

默认情况下,pickle 保存对象的整个 __dict__。但有些字段不该存(如打开的文件句柄、缓存、线程锁),有些字段需要特殊重建逻辑(如重建数据库连接)。

这时要显式定义 __getstate__(决定序列化哪些内容)和 __setstate__(决定反序列化时如何初始化):

def __getstate__(self):
    state = self.__dict__.copy()
    # 排除不可序列化的字段
    state.pop('cache', None)
    state.pop('_db_conn', None)
    return state

def setstate(self, state): self.dict.update(state)

手动重建资源

self._db_conn = self._connect_db()
  • __getstate__ 必须返回一个 pickleable 对象(通常是 dict)
  • __setstate__ 接收的就是这个对象,不一定要调用 __dict__.update,也可完全重新构造
  • 如果类有 __slots____dict__ 不存在,需改用 getattr(self, attr) 显式提取字段

不同序列化方式的性能与兼容性取舍

没有“最好”的序列化方式,只有“更适合当前场景”的选择。关键权衡点是:语言互通性 vs Python 特性支持 vs 体积 vs 速度。

  • pickle:最快、支持所有 Python 类型和引用关系,但仅限 Python,且不安全;适合进程内缓存或可信 RPC
  • json:跨语言、人可读、安全,但丢精度(如 int/float 混淆、无 datetime 原生支持)、体积大;适合 API 响应、配置文件
  • msgpack:二进制、比 JSON 小且快,支持扩展类型(需注册),但默认不支持 Python 特有对象;适合微服务间高效通信
  • pydantic.BaseModel.model_dump_json():自动处理嵌套模型 + datetime + enum,但依赖 pydantic,生成的是 JSON 字符串;适合现代 Python Web 后端

真正容易被忽略的是引用循环和共享对象——pickle 能正确处理,json 直接报错,msgpack 默认也不支持;如果数据结构里有 a.x = b; b.y = a 这种,得提前检测或扁平化。

免责声明:转载请注明出处:http://jing-feng.com.cn/news/782855.html

扫一扫高效沟通

多一份参考总有益处

免费领取网站策划SEO优化策划方案

请填写下方表单,我们会尽快与您联系
感谢您的咨询,我们会尽快给您回复!