Springboot 개인정보 암복호화 저장 (4) 암복호화 시점과 주체 선정 - JPA AttributeConverter
개인정보 암복호화 시점과 주체에 대해 어떤 고민을 하였는 지 공유하겠다. 다른 방법들도 많겠으나 나는 세 가지 후보에 대해서 고려하였고, JPA AttributeConverter를 사용하기로 결정했다. 이를 어떻게 적용하였는 지 간단히 코드를 공개하겠다.
- JPA AttributeConverter
- filter를 이용해 view <-> controller 시점에 변경
- 서비스 단에서 암복호화 함수 사용
암복호화 시점/주체 별 고려사항
1. JPA AttributeConverter
JPA에서 제공해주는 속성 변환기로, 아래 그림과 같이 Java Entity와 DB 사이에서 동작한다. 암복호화 기능 외에도 대소문자 처리나 포맷 변경을 위해서 사용하기도 한다.

장점
- 암복호화 대상이 Entity 클래스에 명확하게 드러나기 때문에 유지보수가 쉬울 것 같다.
- JPA에서 지원하기 때문에 코드가 간결하다.
- service나 view 단에서는 암복호화에 대해 신경을 쓰지 않아도 된다.
단점
- 암복호화를 도메인 단에서 책임지는 게 맞는 지는 잘 모르겠다.
- 이번 프로젝트에서는 외부 API 연동이 주된 서비스이기 때문에, API 송신 시 데이터를 다시 복호화를 해야한다.
2. filter
filter를 사용하면 view <-> controller 시점에 데이터가 암복호화 되니 아래와 같은 장단점이 있을 것 같다.
장점
- JPA 처럼 한 곳에서 암복호화를 관리하니 유지보수가 쉬울 것 같다.
단점
- 요구사항 변화에 유연하지 못하다. 현재는 별다른 처리 없이 암호화된 데이터를 DB에 넣으면 되지만, 요구사항이 바뀌어 서비스에서 데이터를 처리해야하는 경우 코드가 복잡해진다. 컬럼별로 무언가 처리가 필요할 때 마다 service단에 암복호화 로직이 들어가게 된다. controller에서 암호화된 값을 받아서 service에 넘기기 때문에, 데이터의 추가적인 처리가 필요하다면 service에서 다시 복호화 -> 처리 -> DB에 넣기전에 암호화를 해야한다.
- 요구사항 변화 시, 객체 단위로 암복호화할 수 있는 util성 함수를 만들어야 한다.
- 요구사항 변화 시, 누군가 해당 시스템을 인수인계 받아 수정할 때 암복호화 로직을 빼먹을 수 있다.
3. 서비스 단에서 암복호화 함수 사용
장점
- 암복호화는 도메인 로직이 아니기 때문에 service 단에서 책임을 지는 게 맞는 것 같다.
- 암복호화를 함수 단위로 컨트롤이 가능하다.
단점
- DB 데이터를 이용하는 서비스 함수마다 암복호화 로직이 들어가야한다. (신규 기능 추가 시에도 암복호화 로직을 꼭 넣어야함)
- 객체 단위로 암복호화할 수 있는 util성 함수를 만들어야 한다.
- 누군가 해당 시스템을 인수인계 받아 수정할 때 암복호화 로직을 빼먹을 수 있다.
나의 선택
JPA AttributeConverter를 사용하기로 했다.
1. 도메인 로직 변화에 비교적 자유롭다. 현재 개발 중인 시스템은 외부 API에 굉장히 의존적인 시스템이다. 외부에 의해 시스템이 변하고, 내부 시스템보다 변화도를 예측하기 어렵다. 현재는 단순히 고객이 입력한 검진 기록을 저장하고 외부에 송신하지만, 외부 API가 변경되면 송신하는 데이터를 변환해야할 수도 있다.
2. 한 곳에서 관리하는 용이성. 불필요한 암복호화 로직을 여러 군데 추가하고 관리하는 것 보다는 entity 단에서 관리하는 것이 용이할 것이라 판단하였다.
3. DB 조회 시점에서 암복호화를 해주므로, 추가 기능 개발 시 암복호화에 대해 신경쓰지 않고 도메인에 집중 가능
JPA AttributeConverter로 암복호화 적용하기
JPA AttributeConverter 인터페이스를 구현하는 클래스를 작성해보자. 기본적인 형태는 아래와 같다.
@Converter public class CryptoConverter implements AttributeConverter<String, String> { @Override public String convertToDatabaseColumn(String attribute) { return null; } @Override public String convertToEntityAttribute(String dbData) { return null; } }
여기에 암복호화 로직을 넣어보겠다.
@Converter public class CryptoStringConverter implements AttributeConverter<String, String> { @Override public String convertToDatabaseColumn(String attribute) { if (attribute == null) return null; return Seed.encrypt(attribute); } @Override public String convertToEntityAttribute(String dbData) { if (dbData == null) return null; return Seed.decrypt(dbData); } }
다른 타입으로 암복호화를 하고싶은 경우 아래와 같이 타입별로 Converter를 만들면 된다.
@Converter public class CryptoDoubleConverter implements AttributeConverter<Double, String> { @Override public String convertToDatabaseColumn(Double attribute) { if (attribute == null) return null; return Seed.encrypt(attribute.toString()); } @Override public Double convertToEntityAttribute(String dbData) { if (dbData == null) return null; return Double.valueOf(Seed.decrypt(dbData)); } }
타입별로 Converter를 만들다보니 공통적은 코드가 많다는 것이 보인다. 이러면 제네릭을 사용할 수 있지 않을까?하는 생각이 들었다. 시도해보았는데 런타임 오류가 발생하였다. JPA AttributeConverter가 어느 시점에 어떻게 동작하는 지를 잘 모르고, 막연히 변환할 때에 어노테이션 된 필드의 타입으로 매핑해주지 않을까 상상을 했다. 복호화할 시점에 명시적으로 타입이 지정되지 않기 때문에 오류가 발생하는 것으로 추측된다. 왜 오류가 나는 지는 JPA가 어떤 식으로 동작하는 지 차근차근 공부해봐야 알 수 있을 것 같다.
이제 @Entity 클래스의 필드에 AttributeConverter를 적용해보자. 아래와 같이 필드에 @Convert 어노테이션을 달면 JPA가 해당 컬럼에 데이터를 넣고 뺄 때, 내가 작성한 AttributeConverter가 적용되게 된다.
@Entity public class HealthCheckupRecord extends BaseEntity { ... @Convert(converter = CryptoDoubleConverter.class) @Column(columnDefinition = "varchar(24) comment '신장(키)'") private Double height; ... }
이제 암복호화를 위한 개발은 어느정도 마무리되었다.
다음 포스팅에서는 그동안 코드에서 계속 노출되고 있었던 비밀키를 어떻게 관리할 지에 대해 알아보겠다.
비밀키 관리는 이후 서비스 운영, 외부와의 통신 등과 직접적인 관련이 있기 때문에 팀 내 논의 혹은 회사 방침에 따라야한다.
아직 서비스를 한창 개발중이기 때문에 비밀키 관리 방안에 대해 어느 정도 이야기가 된 후에 포스팅할 예정이다.
'Programming > SpringBoot' 카테고리의 다른 글
Jackson Property - Custom PropertyNamingStrategy 적용 (2) | 2020.07.16 |
---|---|
Springboot EhCache 3 - 환경설정부터 self-invocation 처리까지 (6) | 2020.07.12 |
Springboot 개인정보 암복호화 저장 (3) DB에 저장하기(의외의 복병, 인코딩과 모델링) (0) | 2020.06.27 |
Springboot 개인정보 암복호화 저장 (2) 암복호화 알고리즘 - KISA 블록암호 SEED (0) | 2020.06.23 |
Springboot 개인정보 암복호화 저장 (1) A-Z 과정 기록 (0) | 2020.06.21 |
댓글
이 글 공유하기
다른 글
-
Jackson Property - Custom PropertyNamingStrategy 적용
Jackson Property - Custom PropertyNamingStrategy 적용
2020.07.16Jackson에서는 필드명을 직렬화/역직렬화하는 네이밍 전략(PropertyNamingStrategy)을 제공한다. 기본적으로는 카멜 케이스를 제공하고 있으며, 전역적으로 네이밍 전략을 변경하거나 혹은 특정 클래스(DTO)에만 전략을 설정할 수도 있다. 다만, 내가 원하는 '대문자_스네이크_케이스' 전략이 지원 대상이 아니어서 커스텀이 필요한 상황이었다. Camel Case(카멜 케이스) : camelCase Snake Case(스네이크 케이스) : snake_case 내가 원하는 대문자 스네이크 : SNAKE_CASE Jackson이 지원해주는 네이밍 전략은 아래와 같다. PropertyNameingStrategy 클래스에 대한 공식 문서를 살펴보면 자세한 정보를 얻을 수 있다 (일부 네이밍 전략은 S… -
Springboot EhCache 3 - 환경설정부터 self-invocation 처리까지
Springboot EhCache 3 - 환경설정부터 self-invocation 처리까지
2020.07.12Ehcache 3 버전을 Spring Boot에 적용해보겠다. Ehcache 3 버전부터는 JSR-107 cache manager를 구현했다고 한다. 참고로 Spring 4.1버전부터 JSR-107 annotations을 강력하게 지원해주기 시작했다. EhCache 2.x 버전과 3.x 버전의 환경설정 포맷 및 사용방법이 조금 달라졌다. 다들 사용중인 버전에 맞추어 환경설정하기를 바란다. (tti, ttl, expiry 등 캐시 유지기간에 대한 속성을 적용하려면 버전과 환경설정이 일치해야한다.) 다음과 같은 목차로 포스팅을 구성하였다. Ehcache 적용하기 의존성 등록 Spring cache management 활성화(@EnableCache) Ehcache 캐시 설정 캐시 적용 (내부에서 호출되는 경우… -
Springboot 개인정보 암복호화 저장 (3) DB에 저장하기(의외의 복병, 인코딩과 모델링)
Springboot 개인정보 암복호화 저장 (3) DB에 저장하기(의외의 복병, 인코딩과 모델링)
2020.06.27SEED 알고리즘으로 데이터를 암복호화하는 기능까지 구현했다. 이제는 암호화된 데이터를 String 형태로 DB에 저장하고, DB에 암호화된 String 데이터를 복호화하여 보여주면 된다. 이를 위해 두 가지를 진행하면 된다. 1. 암호화된 데이터를 DB에 저장할 수 있는 형태로 변환 (base64나 hex로 인코딩하여 DB에 저장) 2. 암호화된 데이터의 타입과 길이로 테이블의 컬럼 변경 (타입별로 암호화된 데이터 길이 테스트) 이전 코드의 문제점 이전에 구현했던 SEED 클래스와 테스트 코드를 다시 살펴보고 문제점을 확인해보자. public class Seed { private static final byte[] pbszUserKey = "testCrypt2020!@#".getBytes(); priv… -
Springboot 개인정보 암복호화 저장 (2) 암복호화 알고리즘 - KISA 블록암호 SEED
Springboot 개인정보 암복호화 저장 (2) 암복호화 알고리즘 - KISA 블록암호 SEED
2020.06.23암호화 알고리즘을 선택하는 것은 정부 기관 KISA 인터넷진흥원에서 제공하는 표준 안내서를 참고하였다. 데이터 암호화에 대한 가이드는 다른 출처에서도 찾아볼 수 있다. 하지만 KISA의 안내서를 선택한 이유는 KISA가 공신력이 있는 기관이고, 우리나라 법률을 반영한 안내서를 제공하고 있을 것이라는 생각이어서다. 참고로 개인정보에 대한 법률 조항은 기관마다 조금씩 다른데, 이 때는 모두 충족하는 것을 원칙으로 한다. 어떤 알고리즘을 선택해야할까? 데이터의 성격에 따라 암복호화 알고리즘 유형이 다르며, 유형 내에서도 다양한 암복호화 알고리즘이 존재한다. 패스워드는 일방향(해쉬함수) 암호화, 바이오 정보는 블록암호 알고리즘을 선택하기를 권고하고 있다. KISA에서 2017년에 개정한 개인정보 암호화 안내서를…
댓글을 사용할 수 없습니다.