当前位置: 首页 > news >正文

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 成为你系统的后门。

http://www.jsqmd.com/news/1082890/

相关文章:

  • 从67%到82%!AnomalyGPT 实战进阶:Vicuna-7B 升级全记录(附双卡推理方案)
  • shein、亚马逊自养号采购下单技术:跨境采购新利器
  • 3分钟搞定!BetterNCM安装器:网易云音乐插件管理终极神器
  • QQ音乐用遥控笔播放设置
  • paperxie AI PPT 生成器|网页端一站式制作汇报幻灯片,告别熬夜排版
  • HS2-HF_Patch终极指南:5分钟让你的Honey Select 2游戏体验焕然一新
  • 如何快速掌握Sketchfab模型下载:3D爱好者的完整实践指南
  • JMeter汇总报告深度解读:从核心指标到性能瓶颈定位实战
  • 免费跨平台绘图神器:draw.io桌面版完整使用指南
  • AI智能体分类及其应用解析(9)
  • YOLO骨干网络改进-第15篇:EfficientNetV2 compound scaling缩放策略
  • 老Mac焕新终极指南:用OpenCore Legacy Patcher免费升级到最新macOS
  • BetterNCM安装器:3分钟搞定网易云音乐插件一键安装的终极指南
  • Rufus 4.15 Beta发布:修复装机卡死、ARM设备崩溃,还补上两大安全漏洞
  • 从 RNN 到 GPT:大模型架构演化史
  • PS 怎么把人像 p 到另一张照片上?零基础无痕合成完整教程
  • GmSSL架构实战:国密算法在现代安全系统中的深度集成方案
  • 告别DLL错误:Visual C++ Redistributable AIO一键解决Windows程序运行难题 [特殊字符]
  • 凭什么要用余弦退火,不用正弦退火
  • 双材料打印服务,精准定制每一件精品
  • 优刻得GPU+GLM-5+vLLM推理落地实战:A10高性价比部署指南
  • OpenCore Legacy Patcher终极指南:让老Mac重获新生,体验最新macOS系统
  • 6款论文降AI率平台横评:键清零AI痕迹,这款性价比封神
  • Qwerty Learner:解锁键盘工作者的英语肌肉记忆训练新体验
  • 三步解锁小爱音箱音乐自由:你的专属智能音乐管家
  • WindowResizer:3步解决Windows顽固窗口调整难题的终极免费工具
  • 企业微信AI Agent:企微官方能力+企业微信服务商方案+AI SCRM选型指南解读
  • AI 核算真的能降碳吗? - 蓝色星球
  • 036、CA 坐标注意力插入 Backbone(位置一):把位置信息编码进通道注意力的代码
  • AI 与数字化重塑新能源经销服务:下沉市场门店的转型实践拆解