방안 2. 복호화 부분은 ORM Mapper 내 property 를 활용 Cons : - encrypt() 는 호출하고 있는데? - User instance 자체가 복호화된 값을 들고 있지 않은 상태 - property 호출시 마다, 복호화 수행, 암호화 서버라면 네트워크 비용 증가 데이터를 담는 클래스에는 로직을 담는 것은 지양하자는 의견 encrypt(), decrypt() 를 호출하는 곳이 다른 파일/다른 레이어
방안 3. repo 에서 수행 Pros : - DB 암호화이기 때문에 repo 에서 수행하기 적절 - 비지니스 로직 분리 Cons: - insert, update, select 를 사용하는 함수가 많아지면? 비슷한 부분 재작성! - 암호화 해야하는 Table 이 많아지면? 재작성! - 여전히 컬럼별 복호화 이슈
방안 4. SQLAlchemy 의 ORM event 를 활용 DB 암호화와 관련된 QUERY - encrypt : insert, update - decrypt : select 이벤트를 잡아서 처리 할 수는 없을까? Insert, update 가 발생할 때 encrypt() 를 수행? Select 가 발생할 때, decrypt() 를 수행?
방안 4. SQLAlchemy 의 ORM event 를 활용 Pros : - 어느 시점에 암복호화를 하는지 명확 - service, repo 는 순수유지 Cons: - 컬럼별 개별 암복호화 이슈 - Table 이 늘어나면? Handler 증가? 좀 더 좋은 방법이 없을까?
TypeDecorator process_bind_param - APP => DB - DBAPI 의 execute() 함수로 전달될 값(value) 를 전달 받는다. - value serializing, transformation - 주의 : reverse operation - process_result_value()
TypeDecorator process_result_value - APP < = DB - DB 에서 데이터를 가져오는 부분(fetch)에 해당 - a result-row column value to be converted - 주의 : reverse operation - process_bind_param()
결론 SQLAlchemy CustomTypes - TypeDecorator : 기존 타입 + 추가기능 => 사용자 커스텀 타입 - process_bind_param : execute() 로 실행되기전 바인드 되는 값을 조작 - process_result_value : DB 에서 fetch 하는 데이터에 대한 값을 조작
결론 TypeDecorator + DB 암호화 ORM Mapper 클래스 자체에서 Column 별 지정 명시적으로 어떤 컬럼이 암복호화 대상인지 누구나 알 수 있다. 유지보수 암복호화를 호출하는 부분이 EncryptedField 에서만 수행 테스트 용이 복잡도 감소 Business Logic 을 처리하는 service 는 순수 Persistence 에 해당하는 repo 는 ORM 관련 코드만 존재