为什么使用os模块的Python pickle在Windows与Linux间存在序列化差异
问题结论
不是所有使用了os模块的pickle文件都无法跨平台使用,你遇到的报错是序列化了os模块下绑定平台特有实现的可调用对象导致的,属于特定场景的问题。
报错原因
os模块在Python中是平台适配层,不同平台下os暴露的很多接口实际是对应平台专属底层模块的别名:
- Windows环境下
os.system本质是nt.system的引用,它的__module__属性值为nt - Linux环境下
os.system本质是posix.system的引用,它的__module__属性值为posix
pickle序列化可调用对象时,会存储它的所属模块名和对象名,而不是直接保存函数的实现。因此你在Windows生成的pickle流里记录的是「导入nt模块取system方法」,放到没有nt模块的Linux环境反序列化自然会抛出ModuleNotFoundError: No module named 'nt',反过来Windows环境没有posix模块也会报错。
解决方案
你可以通过以下方式避免这类问题:
- 不要直接序列化
os.system这类底层绑定平台模块的可调用对象,自己封装一层接口再序列化:
这种情况下pickle序列化的是你自己定义的import os def my_system(cmd): return os.system(cmd) class PickleRCE(object): def __reduce__(self): return (my_system, ('whoami',))my_system,所属模块是你自己的业务模块,反序列化时只要你的业务模块存在,my_system内部调用的os.system会自动适配当前运行平台的实现,不会出现跨平台报错。 - 如果你需要跨平台、跨Python版本长期存储数据,不要使用pickle,选择json、msgpack等平台无关的序列化方案。同时注意pickle本身存在严重安全风险,永远不要反序列化来源不可信的pickle数据流。
内容的提问来源于stack exchange,提问作者Bmebme
相关产品推荐
相关产品推荐

