Slide 1

Slide 1 text

SQLAlchemy CustomTypes 안성현

Slide 2

Slide 2 text

DB Encryption SQLAlchemy CustomTypes - TypeDecorator - Usage 목차

Slide 3

Slide 3 text

안성현 레이니스트 서버 엔지니어 검색, 결제, 핀테크 발표자 소개 @sh84ahn

Slide 4

Slide 4 text

DB Encryption

Slide 5

Slide 5 text

개인정보 보호법 전자금융업 거래법 WHY?

Slide 6

Slide 6 text

고유식별정보 사용자 이름, 생년월일, 휴대폰 번호, 여권 번호, 주민등록번호 등등 TARGET

Slide 7

Slide 7 text

금융관련 정보 거래정보, 결제정보 등등 TARGET

Slide 8

Slide 8 text

AES256 HOW

Slide 9

Slide 9 text

AES256 SEED HOW

Slide 10

Slide 10 text

AES256 - pycrypto - pycryptodome : PyCryptodome is a fork of PyCrypto HOW

Slide 11

Slide 11 text

SEED - C/C++, ASP, JAVA, PHP - HOW

Slide 12

Slide 12 text

상용 벤더사 - Python 자체로 작성된 것은 전무 - c/c++, .so 파일 연동을 위한 가이드 제시 HOW

Slide 13

Slide 13 text

API PROJECT STRUCTURE PRESENTATION PERSISTENCE API Endpoint Use Case Data BUSINESS LOGIC

Slide 14

Slide 14 text

API PROJECT STRUCTURE PRESENTATION BUSINESS LOGIC PERSISTENCE view.py service.py repo.py

Slide 15

Slide 15 text

API PROJECT STRUCTURE PRESENTATION BUSINESS LOGIC PERSISTENCE view.py service.py repo.py 어디서 암복호화를 해야할까?

Slide 16

Slide 16 text

간단한 예제 사용자의 정보의 저장/조회하는 간단한 서비스 shorturl.at/QRVW1

Slide 17

Slide 17 text

간단한 예제 Presentation Business Logic Persistence Flask 기반의 앱

Slide 18

Slide 18 text

간단한 예제 사용자의 정보를저장하는 테이블

Slide 19

Slide 19 text

간단한 예제 service : 비지니스 로직 처리

Slide 20

Slide 20 text

간단한 예제 repo : ORM 코드 처리

Slide 21

Slide 21 text

방안 1. service 에서 암/복호화 수행 비지니스 로직 + 암복호화

Slide 22

Slide 22 text

방안 1. service 에서 암/복호화 수행 Pros : - DB 관련 부분에서 암호화를 신경 쓸 필요가 없다. - ORM insert, update 코드 그대로 수행.

Slide 23

Slide 23 text

방안 1. service 에서 암/복호화 수행 Cons: - 비지니스 로직을 처리하는 부분에서 수행? - 복호화시 번거로움 : - mapper instance 내 컬럼 변수들이 암호화 되어 있음 - 컬럼별 복호화가 불가피 가장 손쉽게 생각할 수 있는 방법

Slide 24

Slide 24 text

방안 2. 복호화 부분은 ORM Mapper 내 property 를 활용

Slide 25

Slide 25 text

방안 2. 복호화 부분은 ORM Mapper 내 property 를 활용 Pros : - 컬럼의 반복적인 복호화 부분 제거(방안 1에 대한 보완) - decrypt() 를 service 에서 호출하지 않아도 된다.

Slide 26

Slide 26 text

방안 2. 복호화 부분은 ORM Mapper 내 property 를 활용 Cons : - encrypt() 는 호출하고 있는데? - User instance 자체가 복호화된 값을 들고 있지 않은 상태 - property 호출시 마다, 복호화 수행, 암호화 서버라면 네트워크 비용 증가 데이터를 담는 클래스에는 로직을 담는 것은 지양하자는 의견 encrypt(), decrypt() 를 호출하는 곳이 다른 파일/다른 레이어

Slide 27

Slide 27 text

방안 3. repo 에서 수행

Slide 28

Slide 28 text

방안 3. repo 에서 수행 Pros : - DB 암호화이기 때문에 repo 에서 수행하기 적절 - 비지니스 로직 분리 Cons: - insert, update, select 를 사용하는 함수가 많아지면? 비슷한 부분 재작성! - 암호화 해야하는 Table 이 많아지면? 재작성! - 여전히 컬럼별 복호화 이슈

Slide 29

Slide 29 text

방안 4. SQLAlchemy 의 ORM event 를 활용 DB 암호화와 관련된 QUERY - encrypt : insert, update - decrypt : select 이벤트를 잡아서 처리 할 수는 없을까? Insert, update 가 발생할 때 encrypt() 를 수행? Select 가 발생할 때, decrypt() 를 수행?

Slide 30

Slide 30 text

방안 4. SQLAlchemy 의 ORM event 를 활용 ORM Event - Attribute Event - Mapper Event - Instance Event - Session Event - Query Event 다양한 이벤트 제공

Slide 31

Slide 31 text

방안 4. SQLAlchemy 의 ORM event 를 활용 INSERT, UPDATE 시 암호화

Slide 32

Slide 32 text

방안 4. SQLAlchemy 의 ORM event 를 활용 SELECT 시 복호화

Slide 33

Slide 33 text

방안 4. SQLAlchemy 의 ORM event 를 활용 Pros : - 어느 시점에 암복호화를 하는지 명확 - service, repo 는 순수유지 Cons: - 컬럼별 개별 암복호화 이슈 - Table 이 늘어나면? Handler 증가? 좀 더 좋은 방법이 없을까?

Slide 34

Slide 34 text

SQLAlchemy CustomTypes https://docs.sqlalchemy.org/en/13/core/custom_types.html#custom-types

Slide 35

Slide 35 text

Intro

Slide 36

Slide 36 text

Getting Started 간단하게 TestField 를 만들어서 테스트

Slide 37

Slide 37 text

Getting Started Apply TestField

Slide 38

Slide 38 text

Getting Started > repo.get(user_id) process_result_value : 20190101 process_result_value : 홍길동 process_result_value : 01012341234

Slide 39

Slide 39 text

Getting Started > repo.insert(user_name, birthday, phone_number) process_bind_param : 홍길동 process_bind_param : 20190101 process_bind_param : 01012341234

Slide 40

Slide 40 text

SQLAlchemy CustomTypes TypeDecorator Class - 기존 Type에 기능을 추가하는 사용자 지정 Type 작성 가능 - Subclassing of SQLAlchemy’s built-in types

Slide 41

Slide 41 text

TypeDecorator class variable required TypeEngine의 참조 어떤 built-in type 의 subclass 인지 명시

Slide 42

Slide 42 text

TypeDecorator process_bind_param - APP => DB - DBAPI 의 execute() 함수로 전달될 값(value) 를 전달 받는다. - value serializing, transformation - 주의 : reverse operation - process_result_value()

Slide 43

Slide 43 text

TypeDecorator process_result_value - APP < = DB - DB 에서 데이터를 가져오는 부분(fetch)에 해당 - a result-row column value to be converted - 주의 : reverse operation - process_bind_param()

Slide 44

Slide 44 text

TypeDecorator bind_processor, result_processor - processor 함수를 정의해서 넘길 수 있는 형태 - process_bind_param, process_result_value 사용 권장

Slide 45

Slide 45 text

Usage JSON Encoded

Slide 46

Slide 46 text

Usage phone_number masking

Slide 47

Slide 47 text

Usage AmountType https://techspot.zzzeek.org/2011/10/29/value-agnostic-types-part-ii/

Slide 48

Slide 48 text

TypeDecorator + DB Encrypt/Decrypt 컬럼별 복호화 이슈 제거

Slide 49

Slide 49 text

TypeDecorator + DB Encrypt/Decrypt 로직 추가 없이 그대로 사용

Slide 50

Slide 50 text

TypeDecorator + DB Encrypt/Decrypt ORM 그대로 사용

Slide 51

Slide 51 text

TypeDecorator + DB Encrypt/Decrypt 순수 비지니스 로직

Slide 52

Slide 52 text

결론 DB암호화는 필수 사항 어디에서 암호화를 할 것인가? - USE CASE? DATA? 고려해야할 사항: - 암복호화 함수를 호출 하는 부분 이슈 - ORM Mapper 컬럼별 복호화 이슈 - 테스트/유지보수

Slide 53

Slide 53 text

결론 SQLAlchemy CustomTypes - TypeDecorator : 기존 타입 + 추가기능 => 사용자 커스텀 타입 - process_bind_param : execute() 로 실행되기전 바인드 되는 값을 조작 - process_result_value : DB 에서 fetch 하는 데이터에 대한 값을 조작

Slide 54

Slide 54 text

결론 TypeDecorator + DB 암호화 ORM Mapper 클래스 자체에서 Column 별 지정 명시적으로 어떤 컬럼이 암복호화 대상인지 누구나 알 수 있다. 유지보수 암복호화를 호출하는 부분이 EncryptedField 에서만 수행 테스트 용이 복잡도 감소 Business Logic 을 처리하는 service 는 순수 Persistence 에 해당하는 repo 는 ORM 관련 코드만 존재

Slide 55

Slide 55 text

хࢎ೤פ׮.