news 2026/6/26 18:09:20

056、pickle 与序列化:安全性警告、协议版本、替代方案 json、msgpack

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
056、pickle 与序列化:安全性警告、协议版本、替代方案 json、msgpack

056、pickle 与序列化:安全性警告、协议版本、替代方案 json、msgpack

上周帮一个同事排查线上服务崩溃的问题,日志里只留下一行AttributeError: Can't get attribute 'OldModel' on <module '__main__' from ...>。一看就是 pickle 反序列化时类定义变了。这种坑我踩过不止一次,今天干脆把 pickle 的底裤扒干净,顺便聊聊什么时候该换 json 或 msgpack。

序列化到底在干什么

说白了就是把内存里的 Python 对象变成字节流,存文件、发网络、塞 Redis。反过来叫反序列化。pickle 是 Python 自带的,能序列化几乎任何对象——函数、类实例、甚至你自定义的迭代器。但代价就是它只认 Python,而且不安全。

那个让我加班的坑:协议版本

Python 2 时代默认是 protocol 0,文本格式,慢且体积大。Python 3 默认升到 protocol 3,但不同版本之间不总是兼容。我那个同事的坑是这样的:他用 Python 3.8 的 pickle 序列化了一个自定义类的实例,存到 Redis。后来代码重构,类名从OldModel改成了NewModel,反序列化时 pickle 找不到OldModel的定义,直接崩了。

别这样写:直接用默认 protocol 跨版本传输。如果你要长期存储 pickle 文件,或者在不同 Python 小版本间传递,显式指定 protocol 版本:

importpickle# 这里踩过坑:protocol 5 是 Python 3.8+ 才有的# 如果下游是 3.6,直接炸data=pickle.dumps(obj,protocol=4)# 保守点用 4,兼容 3.4+

protocol 版本对照表记一下:

  • 0: 文本格式,最慢,Python 2.3+
  • 1: 二进制格式,Python 2.3+
  • 2: Python 2.3+
  • 3: Python 3.0+,默认
  • 4: Python 3.4+,支持大对象
  • 5: Python 3.8+,支持 out-of-band data

个人建议:跨版本存储一律用 protocol 4,除非你确定所有环境都是 3.8+。

安全性警告:别信外部数据

这是最要命的。pickle 反序列化时会执行任意代码。你从网上、用户输入、甚至内部不信任的服务收到 pickle 数据,直接pickle.loads()等于把服务器钥匙交给别人。

importpickleimportos# 恶意构造的 pickle 数据classEvil:def__reduce__(self):return(os.system,('rm -rf /',))malicious_data=pickle.dumps(Evil())# 这行执行后,你的服务器可能就没了pickle.loads(malicious_data)

别这样写:永远不要对不可信数据用 pickle。内部服务之间用 pickle 也要加白名单或签名。我见过有人把 pickle 数据直接暴露在 HTTP API 里,结果被扫到直接 RCE。

替代方案:json 和 msgpack

json:安全但有限

json 只能序列化基本类型:dict、list、str、int、float、bool、None。自定义对象需要自己写 encoder/decoder。

importjsonfromdatetimeimportdatetimeclassCustomEncoder(json.JSONEncoder):defdefault(self,obj):ifisinstance(obj,datetime):returnobj.isoformat()# 这里踩过坑:忘了抛 TypeError 会导致无限递归returnsuper().default(obj)data={'time':datetime.now(),'name':'test'}json_str=json.dumps(data,cls=CustomEncoder)

json 的好处是跨语言、人类可读、安全。坏处是体积大、不支持 bytes、不支持复杂对象。

msgpack:折中方案

msgpack 像 json 的二进制版本,体积小、速度快、支持 bytes。需要装第三方库msgpack

importmsgpack data={'name':'test','score':95.5,'tags':[1,2,3]}packed=msgpack.packb(data)# 二进制,比 json 小 30% 左右unpacked=msgpack.unpackb(packed)

msgpack 支持自定义类型,但需要写 hook:

importmsgpackfromdatetimeimportdatetimedefencode_datetime(obj):ifisinstance(obj,datetime):return{'__datetime__':True,'value':obj.isoformat()}returnobjdefdecode_datetime(obj):if'__datetime__'inobj:returndatetime.fromisoformat(obj['value'])returnobj packed=msgpack.packb(datetime.now(),default=encode_datetime)unpacked=msgpack.unpackb(packed,object_hook=decode_datetime)

个人建议:内部服务间通信优先用 msgpack,性能好、体积小、安全。对外 API 用 json,兼容性好。只有当你确定数据只在 Python 内部流转、且需要序列化复杂对象(比如函数、类实例)时,才考虑 pickle。

实战经验总结

  1. 永远不要用 pickle 做网络传输。我见过太多人图方便把 pickle 塞进 Redis 或 RabbitMQ,结果版本升级时全崩。用 msgpack 或 json 加自定义序列化,前期多写几行代码,后期少熬几个夜。

  2. pickle 只适合本地缓存或进程间通信。比如你训练了一个机器学习模型,用 pickle 存到本地文件,下次加载。但注意模型类定义不能变,否则反序列化失败。我一般会在 pickle 文件里加个版本号:

importpickleclassModelV1:def__init__(self,params):self.version=1self.params=params# 存的时候model=ModelV1({'lr':0.01})pickle.dump(model,open('model.pkl','wb'))# 加载的时候检查版本loaded=pickle.load(open('model.pkl','rb'))ifloaded.version!=1:raiseValueError('模型版本不匹配')
  1. 如果非要用 pickle,加签名。用 hmac 对 pickle 数据做签名,反序列化前验证,防止篡改。

  2. msgpack 的坑:它不支持set类型,序列化时会变成 list。如果你需要 set,自己转一下。另外 msgpack 的unpackb默认返回 dict,如果你需要有序字典,用object_pairs_hook=collections.OrderedDict

  3. 性能对比:我压测过,序列化 1MB 的 dict,pickle 约 0.5ms,msgpack 约 0.3ms,json 约 0.8ms。反序列化 pickle 约 0.4ms,msgpack 约 0.2ms,json 约 0.6ms。msgpack 在体积和速度上都有优势。

最后说一句:序列化方案选型,先想清楚你的数据要活多久、要跨多少语言、要面对多少安全威胁。别让 pickle 成为你系统的后门。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/26 18:02:57

Fansly下载器终极指南:如何轻松离线保存你喜爱的创作者内容

Fansly下载器终极指南&#xff1a;如何轻松离线保存你喜爱的创作者内容 【免费下载链接】fansly-downloader Easy to use fansly.com content downloading tool. Written in python, but ships as a standalone Executable App for Windows too. Enjoy your Fansly content off…

作者头像 李华
网站建设 2026/6/26 18:02:28

终极指南:Tiled - 免费开源的专业2D地图编辑器

终极指南&#xff1a;Tiled - 免费开源的专业2D地图编辑器 【免费下载链接】tiled Flexible level editor 项目地址: https://gitcode.com/gh_mirrors/ti/tiled 你是否正在寻找一款强大且灵活的2D游戏地图编辑器&#xff1f;Tiled Map Editor正是你需要的解决方案。作为…

作者头像 李华
网站建设 2026/6/26 18:02:21

OFCMS_V1.1.3代码审计

环境搭建 项目地址&#xff1a;ofcms 发行版 - Gitee.com 采用IDEAtomcat进行搭建 数据库配置 修改数据库配置文件&#xff1a;ofcms-V1.1.3\ofcms-admin\src\main\resources\dev\conf\db-config.properties 并且导入数据库 mvn clean package -DskipTests 打包 复制 ofcm…

作者头像 李华
网站建设 2026/6/26 17:58:32

RAG 知识库别只会追加:Java 项目里如何做增量更新

很多团队第一次做 RAG&#xff0c;流程都差不多&#xff1a;上传文档、解析文本、切 chunk、生成 embedding、写入向量库&#xff0c;然后在问答时做相似度检索。Demo 跑通以后&#xff0c;真正的问题才出现&#xff1a;文档更新了怎么办&#xff1f;比如一份《售后政策》从 v1…

作者头像 李华
网站建设 2026/6/26 17:57:51

Unity Mod Manager终极指南:5分钟学会游戏模组管理

Unity Mod Manager终极指南&#xff1a;5分钟学会游戏模组管理 【免费下载链接】unity-mod-manager UnityModManager 项目地址: https://gitcode.com/gh_mirrors/un/unity-mod-manager 你是否曾经因为复杂的模组安装过程而放弃尝试&#xff1f;或者因为模组冲突导致游戏…

作者头像 李华