프로그래밍 언어/JAVA, SPRING

[JPA] 데이터 암/복호화를 위한 @Converter

doomole 2023. 10. 27. 15:12
728x90

이전 프로젝트 들에서는 JPA를 통해 사용자 데이터를 추가/수정/조회 시 @Query를 통해 SQL문을 작성해야만 했다.

전화번호 같은 개인정보 등을 DB에 저장 시 암호화된 데이터로 저장해야 하기 때문이었다. 이를 위해서는 Service 단에서 암/복호화를 수행 후 DB에 작업을 하는 방법이나 mysql AES_ENCRYPT를 통해 명령을 수행하는 방법을 사용했다.

이번에 Converter를 통해 Annotation만으로 손쉽게 암/복호화를 수행하는 방법을 찾게 되어 글을 작성하게 되었다.

 

@Converter 란?

엔티티의 데이터를 변환하여 데이터에 저장할 수 있는 기능

주로 개인정보나 암/복호화 해야하는 정보, 날짜를 원하는 방식으로 저장하기 위해 사용한다.

 

위 글에서는 전화번호의 암/복호화 수행을 하는 Class와 해당 Class의 암복호화 Method를 사용하여 데이터를 변환하는 Converter를 예시로 설명하겠다.

 

DatabaseAesEncryptUtil (암복호화 CLASS)

프로젝트에서 MYSql의 AES_ENCRYPT를 통해 데이터를 암호화 하였으므로 아래의 AES 암/복호화 방식을 사용했다.

import org.apache.commons.codec.binary.Hex;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class DatabaseAesEncryptUtil {
    // 암호화
    public static String encryption(String text, String dbKey) {
        try {
            Cipher cipher = Cipher.getInstance("AES");
            byte[] key = new byte[16];
            int i = 0;
            for(byte b : dbKey.getBytes()) {
                key[i++%16] ^= b;
            }
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
            return new String(Hex.encodeHex(cipher.doFinal(text.getBytes("UTF-8")))).toUpperCase();
        } catch(Exception e) {
            return text;
        }
    }

    // 복호화
    public static String decryption(String encryptedText, String dbKey) {
        try {
            Cipher cipher = Cipher.getInstance("AES");
            byte[] key = new byte[16];
            int i = 0;
            for(byte b : dbKey.getBytes()) {
                key[i++%16] ^= b;
            }
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
            return new String(cipher.doFinal(Hex.decodeHex(encryptedText.toCharArray())));
        } catch(Exception e) {
            return encryptedText;
        }
    }
}

 

AesEncDecConverter (암복호화 컨버터)

Override된 convertToDatabaseColumn가 Entity -> Database로 넣을 때,

convertToEntityAttribute가 Database -> Entity로 입력될 때 수행하는 메서드이다.

위 작성한 class를 통해 암/복호화 된 데이터를 반환한다.

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;

@Converter
public class AesEncDecConverter implements AttributeConverter<String, String> {
	private static dbKey = "암호화키";
    
    @Override
    public String convertToDatabaseColumn(String data){
        return (data != null) ? DatabaseAesEncryptUtil.encryption(data, dbKey) : "";
    }

    @Override
    public String convertToEntityAttribute(String data){
        return (data != null) ? DatabaseAesEncryptUtil.decryption(data, dbKey) : "";
    }
}

 

Member (Entity)

Jpa 테이블 Entity이다. @Convert Annotation을 이용해 Converter class를 등록해주면 해당 컬럼을 이용할 때 Converter method를 통해 데이터를 변환한다.

@Setter
@Getter
@Entity
@Table(name = "TB_MEMBER")
public class Member {

	// 회원 일련번호
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_seq")
    private Long memberSeq;
    
	// 휴대폰번호
    @Convert(converter = AesEncDecConverter.class)
    @Column(name = "mobile_no")
    private String mobileNo;
    
}

 

MemberRepo (repository)

mobileNo를 통한 데이터 조회 시 아래와 같이 메서드를 선언해주는 것만으로도 쉽게 복호화된 데이터를 가져올 수 있다.

@Repository
public interface MemberRepo extends JpaRepository<Member, Long> {

    Member findByMobileNo(String mobileNo);
}

 

 

★ 지적사항이나 피드백은 언제나 환영입니다.