对象序列化和反序列化(反序列化缺陷)

序列化和反序列化概念

序列化:对象序列化是一个用于将(内存中的)对象转换为字节流的过程,序列化后可将其保存到磁盘文件中或通过网络发送到任何其他程序;
反序列化:从字节流创建对象的相反的过程称为反序列化。
百度百科:序列化 (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模块的使用
  1. json.dump()将对象序列化为json格式的字符串写到文件流fp中,e.g:
import json
content = '{"name": "anthony", "sex": "man"}'
with open('text.json', 'w') as f:
    json.dump(content, f)
  1. 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"}
  1. json.dumps()将一个对象序列化为json格式的字符串
>>> b
{'a': 1, 'b': 2}
>>> json.dumps(b)
'{"a": 1, "b": 2}'
  1. json.loads()将json格式的字符串反序列化为一个对象
>>> c='{"a": 1, "b": 2}'
>>> json.loads(c)
{'a': 1, 'b': 2}
4,repr()+eval()
  1. eval() 函数用来执行一个字符串表达式,并返回表达式的值.
    如下可以执行创建对象的语句,如:
>>> x = "{'a': 1, 'b': 2}"
>>> eval(x)
{'a': 1, 'b': 2}
  1. repr() 函数将对象转化为供解释器读取的形式,返回一个对象的 string 格式
>>> a=[1,2,3]
>>> repr(a)
'[1, 2, 3]'

两者结合,可达到"对象<==>字符串"互相转换的效果,如下:

eval(repr(obj)) == obj
Python反序列化缺陷
  1. 漏洞原理
    python反序列化漏洞的本质在于序列化对象的时候,类中自动执行的函数如__reduce__()函数也被序列化,在反序列化时这些函数会直接被执行。如果有人重载了如__reduce__()函数并在其中作手脚,那反序列化时就会导致危险–这是代码注入的一种。
  2. __reduce__()介绍
    __reduce__ must return a string or tuple;
    当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。 reduce 被定义之后,当对象被Pickle时就会被调用。它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组。这个元组包含2到5个元素,其中包括:一个可调用的对象,用于重建对象时调用;一个参数元素,供那个可调用对象使用;被传递给 setstate 的状态(可选);一个产生被pickle的列表元素的迭代器(可选);一个产生被pickle的字典元素的迭代器(可选)
  3. 处理办法–终极办法
    官方文档中说过,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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值