ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Jasypt를 이용한 프로퍼티 암호화
    Security 2021. 9. 1. 08:14

    스프링부트의 프로퍼티 암복호화에 관해서


    일반적을 application.properties 혹은 application.yml 등의 프로퍼티 파일에
    애플리케이션을 구동하기 위한 많은 정보들을 저장합니다.

    이 중에서는 외부에 노출되어서는 안되는 민감한 정보는 평문(Plain Text)로 담기에는 보안적인 이슈가 있어서
    꼭 암호화하여 저장해야 하는 경우가 많이 있습니다.

    이럴때 프로퍼티 암복호화의 일반적인 방법으로 다음과 같은 처리를 많이 합니다.

    1. 암복호화 기능 개발
    2. 평문의 민감 데이터를 암호화하여 암호문을 프로퍼티에 저장
    3. 애플리케이션 구동 중에 프로퍼티에서 암호문을 가져와 복호화 후 사용

     

    위의 방식의 단점은?

    하지만 이와 같은 방법은 여러가지 단점이 있으며 대표적인 것은 다음과 같습니다.

    1. 암복호화를 처리하는 기능을 구현해야 한다. (구현의 복잡성)
    2. 프로퍼티 정보를 스프링 부트 기동시 자동으로 사용해야 할 경우 (자바 소스로 복호화를 할 개입 여지가 없음)

    2번의 단점에 대해서 좀더 자세히 알아보겠습니다.

    첫번째 예로, DB설정등을 예로 들수 있습니다.
    스프링부트에서는 application.properties 혹은 application.yml에 아래와 같이 설정하는 것 만으로도 자바소스 구현 없이 간단히 DB의 접속 및 DBCP 처리를 할 수가 있습니다.

    1
    2
    3
    4
    5
    6
    spring.datasource.hikari.maximum-pool-size=4
     
    spring.datasource.url=jdbc:mysql://{ip}:3306/{db_name}
    spring.datasource.username=db_user
    spring.datasource.password=db_password
     
    cs

    이때 비밀번호를 프로퍼티에 그대로 노출하지 않고 암호화를 하게 되면, 애플리케이션이 구동시에 암호화된 값으로
    DB에 접속을 시도하여 문제가 발생하게 됩니다. (복호화 과정이 없기 때문에)

    두번째 예로는 GIT 연동하는 경우입니다.
    환경설정 서버등을 구현하거나 기타 이유로 어플리케이션에 GIT을 연동해서 쓰는 경우가 있습니다.
    이때도 DB설정과 마찮가지로 프로퍼티 설정만 하면 자바 구현없이 스프링부트가 알아서 GIT과 연동해 줍니다.
    하지만 비밀번호를 암호화된 값을 설정하면 GIT연동시에 오류가 발생하겠지요?

    하지만 Jasypt를 사용하면 이러한 문제가 해결 됩니다.
    어플리케이션이 구동하면서 프로퍼티 정보를 메모리에 올리는데, 이때 Jasypt는 암호화한 정보를 자동으로 복호화 하여 메모리에 로딩하기에 위와 같은 문제점이 해결됩니다.

    또한, Jasypt를 사용하면 암복호화를 잘 알지 못해도 최소한의 노력만으로 쉽게 프로퍼티 암복호화 처리가 가능합니다.

    Jasypt를 이용해서 프로퍼티를 보안 처리 해보자

    Jasypt를 이용하여 간단한 예제를 만들어 보겠습니다.

    예제의 목적
    application.yml에 example.test: "암호문"을 저장하고
    간단한 API를 통해 해당 복호화된 값을 확인하는 예제입니다.

    예제 소스
    이번장에 진행될 소스는 아래 Github에서 다운로드받으시면 됩니다.

     

    Library Dependency (pom.xml)

    예제는 메이븐으로 제작되어 pom.xml에 Jasypt 라이브러리와 Junit을 설정 합니다.
    * Junit은 평문을 암호문으로 만드는 예제로 활용할 것입니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        ..... 중략 .....
    <dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
        ..... 중략 .....
    cs

    Jasypt 환경설정 및 Bean 등록

    다음으로는 Jasypt 환경설정을 구현하고 jasyptStringEncryptor 이름으로 Bean을 등록하였습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Configuration
    public class JasyptConfig {
     
        @Value("${jasypt.encryptor.password}")
        private String encryptKey;
     
        final static String ALGORITHM = "PBEWithMD5AndDES";
     
        @Bean("jasyptStringEncryptor")
        public StringEncryptor stringEncryptor() {
            PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
            SimpleStringPBEConfig config = new SimpleStringPBEConfig();
            config.setPassword(encryptKey);
            config.setAlgorithm(ALGORITHM);
            config.setKeyObtentionIterations("1000");
            config.setPoolSize("1");
            config.setProviderName("SunJCE");
            config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
            config.setStringOutputType("base64");
            encryptor.setConfig(config);
            return encryptor;
        }
    }
    cs

     

    Jasypt 암복호화 Secret Key 설정하기

    이제 암복호화를 처리하기 위한 Secret Key를 설정해야 합니다.
    보안을 위해 키는 운영체제 환경설정으로 등록하거나, 어플리케이션 기동시에 VMOption으로 등록할수도 있으나
    예제의 편의성을 위해 application.yml에 저장하도록 하겠습니다.
    * 실제 운영시에는 프로퍼티가 아닌 다른 방법을 권장드립니다.

    1
    2
    3
    4
    5
    jasypt:
      encryptor:
        bean: jasyptStringEncryptor
        password: jasypt_key
     
    cs

    Jasypt 환경설정에 등록한 jasyptStringEncryptor Bean의 Secret Key로 "jasypt_key"를 설정하였습니다.

    여기까지가 Jasypt를 사용하기 위한 설정 입니다.
    이제 남은 것은 "암호화"문을 프로퍼티에 등록하고, 이를 확인하는 예제 API를 만들어 보겠습니다.

    평문을 암호화 하여 프로퍼티에 등록

    JUnit 예제를 이용해서 평문의 암호문을 만들어 보겠습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = JasyptTest .class)
    public class JasyptTest {
     
        @Value("${jasypt.encryptor.password}")
        private String encryptKey;
     
        @Test
        public void encryptDecryptTest() {
            String text = "plain-text"// 암호화 대상 평문
     
            StandardPBEStringEncryptor jasypt = new StandardPBEStringEncryptor();
            jasypt.setPassword(encryptKey); // Jasypt를 이용하여 암호화하는 키 (프로퍼티의 jasypt.encryptor.password)
            jasypt.setAlgorithm("PBEWithMD5AndDES"); // Jasypt를 이용한 암호화 알고리즘
     
            String encryptedText = jasypt.encrypt(text);
            System.out.println("enc : " + encryptedText);
            String decryptedText = jasypt.decrypt(encryptedText);
            System.out.println("dec : " + decryptedText);
        }
    }
    cs

    해당 Junit을 수행하면 프로퍼티에 등록된 Secret Key를 이용하여 "plain-text" 문자열을 암호화 합니다.

    출력된 암호문을 프로퍼티에 등록합니다.
    등록시 주의하실 사항은 암호문을 반디스 ENC( ..... ) 로 감싸서 등록하여야 합니다. 그래야 Jasypt는 복호화할 대상을 인식할 수 있습니다.

    1
    2
    example:
      test: ENC(oPhGpXZf5F8FM2FaPTVDNC142BFU5ObW)
    cs

     

    복호화된 평문 확인 API 예제

    모든 구현이 끝났으니 정말로 암호화된 프로퍼티가 복호화 된 채로 메모리에 로딩되어 있는지, 프로퍼티의 값을 확인하는 API 예제를 하나 만들어 보겠습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Slf4j
    @RestController
    public class JasyptSimpleController {
     
        @Value("${example.test}")
        private String exampleProperty;
     
        @GetMapping(value = "/property")
        public String property() {
            return exampleProperty;
        }
    }
    cs
     
    @Value 어노테이션으로 프로퍼티의 값을 가져와 반환하는 단순한 예제 입니다.
     
     
    이제 어플리케이션 기동 후 브라우저로 "http://localhost:8080/property" API를 호출해 보면 정상적으로 복호화된 평문이 반환된 것을 확인하실 수 있습니다. 

    http://localhost:8080/propert

     

    댓글

Designed by Tistory.