1. pickle?
직렬화 : 개체를 메모리, DB, 파일에 저장하기 위해 개체를 바이트 스트림으로 변환하는 프로세스
언어마다 직렬화를 표현하는 단어가 다르다.
java : 직렬화
python : 피클링
perl.. etc : 마샬링
사실 마샬링이 가장 큰 개념이다. 직렬화하는 모든 과정을 뜻하는 말이다.
2. 난 json 잘 쓰고 있는데?
pickle vs json
pickle과 JSON (JavaScript Object Notation) 에는 근본적인 차이가 있다.
- JSON은 텍스트 직렬화 형식(유니코드 텍스트를 출력하지만, 대개는 utf-8으로 인코딩)인 반면, pickle은 바이너리 직렬화 형식
- JSON은 사람이 읽을 수 있지만, pickle은 그렇지 않다
- JSON은 상호 운용이 가능하며 파이썬 생태계 외부에서 널리 사용되는 반면, 피클은 파이썬으로만 한정됨
- JSON은 기본적으로 파이썬 내장형 일부만 표시할 수 있으며 사용자 정의 클래스는 표시할 수 없다.
- pickle과 달리 JSON의 역직렬화는 그 자체로 임의 코드 실행 취약점을 만들 수 없다.
3. pickle 사용법
3-1 변수 저장
1
2
3
4
5
6
7
|
data = {
'a': [1, 2.0, 3, 4+6j],
'b': ("character string", b"byte string"),
'c': {None, True, False}
}
pickle.dumps(data)
# b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01]q\x02(K\x01G@\x00\x00\x00\x00\x00\x00\x00K\x03cbuiltins\ncomplex\nq\x03G@\x10\x00\x00\x00\x00\x00\x00G@\x18\x00\x00\x00\x00\x00\x00\x86q\x04Rq\x05eX\x01\x00\x00\x00bq\x06X\x10\x00\x00\x00character stringq\x07C\x0bbyte stringq\x08\x86q\tX\x01\x00\x00\x00cq\ncbuiltins\nset\nq\x0b]q\x0c(\x89\x88Ne\x85q\rRq\x0eu.'
|
cs |
3-2 함수 , 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
def test(val):
print("이것은", val, "이다")
p = pickle.dumps(test)
t = pickle.loads(p)
t("발") # 이것은 발 이다
# ======================================================
class Bar:
def __init__(self, data=None):
print("init start", data)
def __call__(self):
print("call")
p = pickle.dumps(Bar)
data = pickle.loads(p)
data() # init start None
data("bar class")() # init start bar class
|
cs |
3-3 파일 저장
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Foo:
attr = 'A class attribute'
# save
with open('data.pickle', 'wb') as f:
pickle.dump(Foo, f)
# load
with open('data.pickle', 'rb') as f:
data = pickle.load(f)
print(data.attr) # A class attribute
|
cs |
다음 형태를 pickle 할 수 있다
- None, True와 False
- 정수, 실수, 복소수
- 문자열, 바이트 열, 바이트 배열(bytearray)
- 피클 가능한 객체만 포함하는 튜플, 리스트, 집합과 딕셔너리
- 모듈의 최상위 수준에서 정의된 함수
- 모듈의 최상위 수준에서 정의된 내장 함수
- 모듈의 최상위 수준에서 정의된 클래스
한마디로 그냥 인스턴스 할 수 있는 모든 것이 다 됨.
3. 머신러닝에서의 pickle
실습 파일
4. pickle 사용 시 주의할 점
- pickle에서 실행 중인 객체와 설치된 패키지의 버전이 동일해야 한다.
- 안전하지 않은 역직렬화
실행 가능한 코드로 전달되기 때문에 안전하지 않은 역직렬화 취약점은 결국 Injection 공격을 허용한다.
아무 파일이나 pickle 실행하면 망하는 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import os
import pickle
class Exploit(object):
def __reduce__(self):
return (os.system, ('whoami',))
def serialize_exploit():
shellcode = pickle.dumps(Exploit())
return shellcode
def insecure_deserialization(exploit_code):
pickle.loads(exploit_code)
shellcode = serialize_exploit()
insecure_deserialization(shellcode) # uiandwe
|
cs |
번외 1
python에도 marshal을 지원하지만, 내부 파이썬 객체 직렬화 즉. pyc에서 사용하며, pickle에 비해 적용 가능한 범위가 적어 사용을 권장하지 않는다.
1
2
3
4
|
import marshal
m = marshal.dumps(user) # b'\xfb\xda\x04namez\tseung jae\xda\x08positionz\x10Backend Engineer0'
marshal.loads(m) # {'name': 'seung jae', 'position': 'Backend Engineer'}
|
cs |
번외 2
python에서 변수를 파일로 저장할 때는 shelve 패키지를 지원하지만, 내부적으로 pickle를 사용하고 있기에, 딱히 구분해서 쓸 필요는 없다. shelve는 객체가 아닌 변수만 가능한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import shelve
d = shelve.open("shelve_test")
d['xx'] = [0, 1, 2]
d['xx'].append(3)
temp = d['xx']
temp.append(5)
d['xx'] = temp
d.close()
# =========================================
d = shelve.open("shelve_test")
for key in d.keys():
print(key, d[key])
# xx [0, 1, 2, 5]
|
cs |
참조
https://www.acunetix.com/blog/articles/what-is-insecure-deserialization/
https://docs.python.org/ko/3/library/pickle.html
https://docs.python.org/ko/3/library/marshal.html#module-marshal
https://statkclee.github.io/nlp2/nlp-ml-deployment.html
'app > python' 카테고리의 다른 글
ERROR: Cannot install -r /requirements.txt because these package versions have conflicting dependencies. (0) | 2021.07.26 |
---|---|
parquet (0) | 2021.07.05 |
pip multiple versions of dependency resolver problem (1) | 2021.06.10 |
파이썬 부동소수점 사용시 주의할점 (1) | 2021.06.09 |
array의 연산을 빠르게 하는 방법 (0) | 2021.04.09 |