序列化和反序列化概念
序列化:对象序列化是一个用于将(内存中的)对象转换为字节流的过程,序列化后可将其保存到磁盘文件中或通过网络发送到任何其他程序;
反序列化:从字节流创建对象的相反的过程称为反序列化。
百度百科:序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象
python中的序列化和反序列化api
1,pickle模块的使用
pickle模块使用二进制协议去序列化和反序列化一个python对象;
Pickling”(也就是Serialization序列化) 是一个python对象呢转换为一个字节流的过程;
“unpickling”( 也即deserialization反序列化)是相反的过程,即将一个字节流(一个二进制文件或字节对象)转换为python对象;
(1) pickle.dump(obj, file, [,protocol])
函数的功能:将obj对象序列化存入已经打开的file中(注意将对象的类型及层次结构等信息也存入文件了,这样在反序列化的时候就知道怎么构建还原对象了)。
参数讲解:
obj:想要序列化的obj对象。
` file:文件名称。
protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
(2)pickle.load(file)
函数的功能:将file中的对象序列化读出。
参数讲解:
file:文件名称。
(3)pickle.dumps(obj[, protocol])
函数的功能:将obj对象序列化为string形式,而不是存入文件中。
参数讲解:
obj:想要序列化的obj对象。
protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
(4)pickle.loads(string)
函数的功能:从string中读出序列化前的obj对象。
参数讲解:
string:文件名称。
【注】 dump() 与 load() 相比 dumps() 和 loads() 还有另一种能力:dump()函数能一个接着一个地将几个对象序列化存储到同一个文件中,随后调用load()来以同样的顺序反序列化读出这些对象。
代码示例
#coding:utf-8
__author__ = 'MsLili'
#pickle模块主要函数的应用举例
import pickle
dataList = [[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']]
dataDic = { 0: [1, 2, 3, 4],
1: ('a', 'b'),
2: {'c':'yes','d':'no'}}
#使用dump()将数据序列化到文件中
fw = open('dataFile.txt','wb')
# Pickle the list using the highest protocol available.
pickle.dump(dataList, fw, -1)
# Pickle dictionary using protocol 0.
pickle.dump(dataDic, fw)
fw.close()
#使用load()将数据从文件中序列化读出
fr = open('dataFile.txt','rb')
data1 = pickle.load(fr)
print(data1)
data2 = pickle.load(fr)
print(data2)
fr.close()
#使用dumps()和loads()举例
p = pickle.dumps(dataList)
print( pickle.loads(p) )
p = pickle.dumps(dataDic)
print( pickle.loads(p) )
2,cPickle模块的使用
cPickle和pickle一样,两者只是实现的语言不同,一个是C实现,另一个是纯Python实现,函数调用基本相同,但cPickle库的性能更好。
cPickle API接口如下:
cPickle.dump():将Python对象序列化保存到本地的文件中。
cPickle.load():载入本地文件,将文件内容反序列化为Python对象。
cPickle.dumps():将Python对象序列化为字符串。
cPickle.loads():将字符串反序列化为Python对象。
3,json模块的使用
- json.dump()将对象序列化为json格式的字符串写到文件流fp中,e.g:
import json
content = '{"name": "anthony", "sex": "man"}'
with open('text.json', 'w') as f:
json.dump(content, f)
- json.load()从文件流fp中读取json格式的字符串并将其反序列化为对象,e.g:
import json
with open('text.json', "r") as f:
a = json.load(f)
print(a) #{"name": "anthony", "sex": "man"}
- json.dumps()将一个对象序列化为json格式的字符串
>>> b
{'a': 1, 'b': 2}
>>> json.dumps(b)
'{"a": 1, "b": 2}'
- json.loads()将json格式的字符串反序列化为一个对象
>>> c='{"a": 1, "b": 2}'
>>> json.loads(c)
{'a': 1, 'b': 2}
4,repr()+eval()
- eval() 函数用来执行一个字符串表达式,并返回表达式的值.
如下可以执行创建对象的语句,如:
>>> x = "{'a': 1, 'b': 2}"
>>> eval(x)
{'a': 1, 'b': 2}
- repr() 函数将对象转化为供解释器读取的形式,返回一个对象的 string 格式
>>> a=[1,2,3]
>>> repr(a)
'[1, 2, 3]'
两者结合,可达到"对象<==>字符串"互相转换的效果,如下:
eval(repr(obj)) == obj
Python反序列化缺陷
- 漏洞原理
python反序列化漏洞的本质在于序列化对象的时候,类中自动执行的函数如__reduce__()函数也被序列化,在反序列化时这些函数会直接被执行。如果有人重载了如__reduce__()函数并在其中作手脚,那反序列化时就会导致危险–这是代码注入的一种。 - __reduce__()介绍
__reduce__ must return a string or tuple;
当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。 reduce 被定义之后,当对象被Pickle时就会被调用。它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组。这个元组包含2到5个元素,其中包括:一个可调用的对象,用于重建对象时调用;一个参数元素,供那个可调用对象使用;被传递给 setstate 的状态(可选);一个产生被pickle的列表元素的迭代器(可选);一个产生被pickle的字典元素的迭代器(可选) - 处理办法–终极办法
官方文档中说过,pickle是个不安全的模块,永远别去反序列化不信任的数据.
Python反序列化缺陷攻击举例
# -*- coding: utf-8 -*-
# @Author: Administrator
# @Date: 2019-09-05 09:00:45
# @Last Modified by: Administrator
# @Last Modified time: 2019-09-07 14:57:20
import pickle
# class Mytest(object):
class Mytest:
# 重载父类的__reduce__
def __reduce__(self):
print("reduce is execute!")
return super().__reduce__()
# 注意class本身也是一个对象
# 现在我们尝试将这个class进行序列化
seri_temp = pickle.dumps(Mytest)
print(seri_temp) # b'\x80\x03c__main__\nMytest\nq\x00.'
# 反序列化看看__reduce__会不会执行
deseri_temp = pickle.loads(seri_temp) # 在反序列化的时候没有任何反应
print(deseri_temp) # <class '__main__.Mytest'>
# 定义一个该类的实例看看会不会执行
object_temp = Mytest()
seri_temp = pickle.dumps(object_temp)
pickle.loads(seri_temp) # reduce is execute! 在反序列化的时候执行了!
运行结果:
b'\x80\x03c__main__\nMytest\nq\x00.'
<class '__main__.Mytest'>
reduce is execute!
[Finished in 0.1s]