ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] Jasypt를 통한 암복호화 - application.properties에서 db 암호화
    개발기록 2022. 9. 21. 14:00
    반응형
    728x90

     

    개요

    현재 프로젝트는 gradle이며, 멀티모듈을 시도하고 있다.

    이에 맞는 코드가 구글링했을 때, 테스트코드와 멀티모듈 시 어떻게 하는 지에 대해서 딱히 안 나와서 참고하는 블로그 글을 토대로 프로젝트에 맞게 바꾸고 기록한다.

    암복호화에 사용될 알고리즘으로 PBEWithMD5AndDES을 사용했다.

     

    개발 순서 및 코드

    1. build.gradle

    build.gradle에 필요한 dependency들을 추가한다.

    dependencies {
        // 설정파일 암호화 dependency
        // https://mavenlibs.com/maven/dependency/com.github.ulisesbocchio/jasypt-spring-boot
        api 'com.github.ulisesbocchio:jasypt-spring-boot:3.0.4'
        // 암호 알고리즘 dependency
        // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15to18
        api 'org.bouncycastle:bcprov-jdk15to18:1.71'
    }

     

    2. JasyptConfig.java

    PBEWithMD5AndDES 알고리즘을 사용하여 이번 게시물에서 가장 핵심인 JasyptConfig.java를 만든다.

    password의 경우 하드코딩보다는 application.properties에서 프로퍼티로 선언하고 가져다 쓰는 방식을 쓰기로 한다.

     

    2-1. application.properties

    # Jasypt Config
    jasypt.encryptor.password=test
    jasypt.encryptor.property.prefix=ENC(
    jasypt.encryptor.property.suffix=)

    jasyptConfig.java에서 해당 프로퍼티를 변수로 선언해서 사용한다.

     

    2-2. JasyptConfig.java

    package com.??.config;
    
    import com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesConfiguration;
    import org.jasypt.encryption.StringEncryptor;
    import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
    import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @Configuration
    @Import(EnableEncryptablePropertiesConfiguration.class)
    public class JasyptConfig {
    
        @Value("${jasypt.encryptor.password}")
        private String jasyptPassword;
        
        @Bean("jasyptEncryptor")
        public StringEncryptor stringEncryptor() {
            PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPassword(jasyptPassword); // 암호화 키
            config.setAlgorithm("PBEWithMD5AndDES"); // 알고리즘
            config.setKeyObtentionIterations("1000");
            config.setPoolSize("1");
            config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
            config.setStringOutputType("base64");
            encryptor.setConfig(config);
            return encryptor;
        }
    }

     

    위 코드에서

    @Import(EnableEncryptablePropertiesConfiguration.class)

    를 안 써주면

    import com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesConfiguration;

     

    import 구문이 적용 안 되면서 에러를 발생시킨다.

    이유에 대해서는 더 공부해봐야겠다,,

    이 부분을 구글링해서 해결하는데 애먹었던 기억이있다,,

    하지만 이미 다 구현한 후 게시물을 작성하며 정리하고 있기 때문에 참고한 게시물 출처는 어디인 지 모르겠다,,

     

    3. Test코드 작성

    Assertions.assertThat 코드를 사용해서 암복호화가 제대로 작동하는 지 확인한다.

    ※ 콘솔에 찍어보고 싶으면 log.info()를 사용한다. 이 경우에 @Slf4j를 사용하기 위해서 필요한 의존성을 추가해줘야한다.

    package com.??.config;
    
    import org.assertj.core.api.Assertions;
    import org.jasypt.encryption.StringEncryptor;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    
    @SpringBootTest(classes = JasyptConfig.class)
    public class JasyptConfigTests {
        final BeanFactory beanFactory = new AnnotationConfigApplicationContext(JasyptConfig.class);
        final StringEncryptor stringEncryptor = beanFactory.getBean("jasyptEncryptor", StringEncryptor.class);
    
        @Test
        @DisplayName("암복호화 테스트")
        void encryptorTest() {
            String keyword = "plain text";
            String enc = stringEncryptor.encrypt(keyword);
            String des = stringEncryptor.decrypt(enc);
            assertThat(keyword).isEqualTo(des);
    
            // 틀릴 경우 에러
    //        Assertions.assertThat(keyword).isEqualTo(enc); // 에러
    //        Assertions.assertThat(enc).isEqualTo(des); // 에러
        }
    }

    Test코드를 작성한다고 java의 reflection과 asserThat을 구글링하면서 찾아봤던 기억이 난다.

    이 부분에 대해서는 날잡고 따로 정리를 한 번 해야겠다.

    cf) asserThat을 썼을 때 틀릴 경우 에러가 발생한다.

     

    4. 상속

    core가 되는 모듈에서 암복화를 구현했다. 현재 프로젝트는 멀티모듈을 시도하고 있기 때문에 다른 모듈에서 사용할 때에는 해당 클래스(JasyptConfig.java)를 상속받아 사용한다.

    package com.????.config;
    
    import com.kvaram.??.JasyptConfig;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ChildJasyptConfig extends JasyptConfig {
    }

    ※ core 모듈의 의존성들을 그대로 사용할 경우, 해당 모듈의 build.gradle

    만약 core 모듈 명이 jeongwoo-core라면 implementation project(':jeongwoo-core')로 적어주면 된다.

     

    ex)

    dependencies {
        implementation project(':core가 되는 모듈명')
    }

     

    5. application.properties 적용

    jasypt.encryptor.bean=jasyptEncryptor 을 명시하여 jasyptEncryptor의 이름을 가진 Bean이 복호화할 것임을 알려준다.

    # Jasypt Config
    jasypt.encryptor.bean=jasyptEncryptor
    jasypt.encryptor.password=test
    jasypt.encryptor.property.prefix=ENC(
    jasypt.encryptor.property.suffix=)
    
    # DB Connection Information
    spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
    spring.datasource.url=ENC("암호화된 문자열")
    spring.datasource.username=ENC("암호화된 문자열")
    spring.datasource.password=ENC("암호화된 문자열")

    ※ cf) Test 코드에서 암복호화가 필요한 문자열을 암호화한다.

    암호화된 문자열을 ENC()안에 적고 사용한다(단, 이때 ""로 묶어줄 필요는 없다.).

     

    ex) 

    spring.datasource.username=ENC(testEncString)

     

    가장 중요한 것은 password이다. 도중에 password를 바꾼다면 기존에 있던 암호화된 문자열들을 사용할 수 없다.

    따라서 도중에 password를 바꾸고싶다면 바꾼 password로 다시 암호화한 후 반환된 문자열을 사용해야한다.

     

    참고: https://dejavuhyo.github.io/posts/encrypt-configuration-file-in-springboot/

     

     

    728x90
Designed by Tistory.