본문 바로가기
  • hazard_dev@__
  • hazard_dev@__
Python

[Python] pickle 라이브러리는 왜 써야 될까?

by Hazard3_o00sung 2023. 4. 5.
728x90

강력하고 아름다운 언어 Python 입니다.

[Python] pickle 라이브러리는 왜 써야 될까?

  pickle 라이브러리를 사용해서 일부 모듈을 구현하던 중, 의문이 생겼습니다. 이렇게 편리하고 좋은 라이브러리를 어떻게 사용하는 것이 효율적이고 적절한가 입니다. pickle 라이브러리에 대해서 공식적인 소개글을 한번 보도록 하겠습니다.

pickle 공식 설명

위의 설명만 보면은 어떻게 사용하는 것이 좋은지 어떻게 사용해야할지 감이 잡히지 않습니다. 왜냐하면 파이썬 객체 구조의 직렬화와 역 직렬화에 대한 이해가 우선되어야 하기 때문입니다. 데이터의 직렬화는 데이터를 바이트 스트림 형태로 변환하는 과정을 의미하게 되는데, 데이터를 이진화로 변환해야 네트워크 전송 등에 유리하기 때문입니다.  바이트 스트림은 1byte 를 입출력하게 해주는 스트림입니다! 그러니, 파일 전송, 음악 스트리밍 등등 데이터 손실률 줄이는 작업에서 유리하다는 것이죠. 사용법은 보기보다 간단한 편입니다. 그리고 파이썬의 모든 객체를 바이트 스트림화 할 수 있으니, 어떤 분야에서건 데이터 사이즈가 큰 경우에는 pickle 을 사용해서 데이터를 직렬화해두고 load 하는 것이 유리하기도 합니다!

 

코드 예제

코드 예제는 보기보다 간단한 편입니다.

import pickle
import os

if os.path.exists("test.pickle"):
	print("already exists")
else:
	print("generate require")
    
    
# 파일에서 객체를 읽어옴
with open('test.pickle', 'rb') as f:
    my_list = pickle.load(f)

# 복원된 객체 사용
print(my_list)  # [1, 2, 3, 4, 5]

위와 같이 사용하는 것이 기본적인 사용방법입니다. 우선 os.path.exists 함수로 파일이 실제로 있는지 확인하는 함수는 그냥 제 코드에서 긁어온거라 그냥 넘겨주세요(ㅋㅋ;) 일단 예제에서는 리스트를 pickle 화 하였으나, 클래스 또는 딕셔너리 등 모든 객체를 직렬화 할 수 있습니다. 이번엔 딕셔너리를 직렬화하는 코드를 보겠습니다.

def to_pickle(data):
    with open(PICKLE_PATH, "wb") as file:
        pickle.dump(data, file)
    file.close()
    
def pickle_to(data):
    with open(PICKLE_PATH, "rb") as file:
        data = pickle.load(file)
    file.close()    
    return data
    
#모든 pickle은 w, r 등의 io 타입으로 할 수 없습니다.
#wb, rb 등 바이트 스트림으로만 io 할 수 있습니다.

위와같은 함수를 생성할 수 있습니다. PICKLE_PATH 는 글을 읽으시는 분께서 직접 경로를 지정해주시면 됩니다. 아래와 같이 dict 를 상속받은 클래스를 pickle화 하고 파이썬 객체화하는 방법에 대해서 알아보겠습니다.

class TestStructure(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    
    def __getstate__(self):
        return self.copy()
    
    def __setstate__(self, state):
        self.update(state)
        
ts = TestStructure()
test = {1:1, 2:2}

ts.update(test)

# pickle 화 합니다.
to_pickle(ts)

# 파이썬 객체화 ( 역직렬화 ) 를 진행합니다
pickle_to(ts)

위와 같이 사용할 수 있겠습니다. 생각보다 간단하긴 하지만 보안상으로 알아두어야 할 내용들이 있습니다. 아무 pickle이나 역직렬화해서 사용하는 것은 보안상으로 좋지 않다는 것입니다.

pickle 보안 경고

안전하지 않은 이유는 이것입니다. 코드를 보면 아시다시피 역직렬화 하는 과정 중 보안 사항이 없습니다. 일종의 key 값이 없기 때문에 어떤 데이터든 묻지도 따지지도 않고 역직렬화한다는 것인데요. 따라서, hmac 라이브러리를 함께 사용해서 보안화 시켜주는 것이 좋습니다. 물론 산업계에서 그렇게 하시는게 좋지. 일반적인 즉, 개인적인 프로젝트에서는 그냥 사용하는 것이 편합니다; 굳이 직렬화 할 때 보안화 할 필요 없다는 것이죠. 

 

HMAC 알고리즘

Hierarchical Message Authentication Code 의 줄임말이며, 메시지 인증 코드( mac ) 의 일종으로 메시지 무결성을 확인하기 위해 사용하는 암호화 기술 정도로 알려져 있습니다. 일반적으로 hashlib 과 함께 사용합니다. pickle 과 함께 사용해서 pickle 의 바이트 스트림 서명 값을 생성하고 함께 저장하여 암호화하는 코드를 간단하게만 보겠습니다.

import pickle
import hmac
import hashlib

# 객체 생성
data = {1: 1, 2: 2}

# 객체 직렬화
data_pickle = pickle.dumps(data)

# HMAC 알고리즘 사용을 위한 키 생성
key = b"hmac_algorithm_test_key"

# 바이트 스트림에 대한 서명 값을 생성
signature = hmac.new(key, data_pickle, hashlib.sha256).digest()

# 객체와 함께 서명 값을 저장
with open("data.pickle", "wb") as f:
    pickle.dump((data_pickle, signature), f)

위와 같이 암호화를 진행했습니다. 이제 당연히 복호화하는 코드도 한번 보도록 하겠습니다.

import pickle
import hmac
import hashlib

# 객체와 함께 저장된 서명 값을 불러옴
with open("data.pickle", "rb") as f:
    data_pickle, signature = pickle.load(f)

# HMAC 알고리즘 사용을 위한 키 생성
key = b"hmac_algorithm_test_key"

# 바이트 스트림에 대한 서명 값을 계산
computed_signature = hmac.new(key, data_pickle, hashlib.sha256).digest()

# 서명 값이 일치하는지 확인
if hmac.compare_digest(signature, computed_signature):
    # 서명 값이 일치하면 객체 복원
    data = pickle.loads(data_pickle)
    print(data)
else:
    print("Decode Fail")

위와 같이 복호화 할 수 있습니다. 이런게 있구나 정도로만 이해하시고 넘어가셔도 될 것 같습니다. 직접 코드를 작성해보실 분들은 코드를 작성하셔도 좋을 것 같구요!

 

결론

  • pickle 을 사용해서 데이터를 바이트 스트림으로 직렬화 하여 파이썬에서 데이터를 여유롭게 다뤄봅시다.
  • pickle 은 모든 파이썬 객체를 직렬화할 수 있습니다.
  • pickle 을 보안상 이슈(?) 가 있기 때문에 대외용으로 스크립트가 수행되어야할 때는 암호화 알고리즘을 적용하자

읽어주셔서 감사합니다~~

728x90

댓글