[Java] Spring 프로퍼티 암복호화 - Jasypt 사용법 및 에러 해결

Nowod_K·2023년 2월 3일
1

Jasypt가 필요했던 이유

보통 Spring을 사용할 때 .properties 파일을 활용하여 웹어플리케이션을 구동하거나, DB 연결 등 필요한 정보들을 담아둔다.

개인적인 프로젝트나, 보안이 중요하지 않은 프로젝트에서는 그런 정보들을 관리할 필요가 없다. 하지만 고객정보나, 중요한 키값들이 담겨있는 경우에는 암호화가 필요하다.

이번에 주요정보 암복호화에 대한 요건이 생기면서, KMS(Key Managment System)을 통해 주요 키값을 가져와야 했다.

KMS (Key Management System)이란?

  • 암호화 키를 관리하는 시스템으로 키의 생성, 저장, 복구 등 키값의 라이프사이클을 관리하는 시스템이다.

주요 키값을 가져오려면 키값을 확인하기 위한 파라미터들이 필요하다. 사실 키값을 가져오기 위한 파라미터도 주요 정보였고, 이 파라미터를 암복호화 하기 위해서 Jasypt를 사용하게 되었다.

Jasypt

Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.
출처 : http://www.jasypt.org/

Jasypt는 암복호화를 깊이 이해하지 않더라도 개발자가 손쉽게 사용할 수 있도록 만들어진 라이브러리다. 공식 홈페이지를 가보면 Spring, hibernate와 같이 Spring에 특화되어서 만들어진 라이브러리 이기에 스프링을 사용하는 프로젝트라면 어디든 적용할 수 있다.

현재 적용할 프로젝트는 Spring 4로 되어있어서 문제없이 적용할 수 있었다.
Jasypt를 적용하는 흐름은 다음과 같다.

  1. Jasypt 라이브러리 적용
  2. Jasypt를 이용하여 암호화 및 프로퍼티 적용
  3. Spring context.xml을 활용하여 프로퍼티 복호화

Jasypt 라이브러리 적용

라이브러리 적용은 간단하다. maven을 사용중이면 pom.xml을 통해 적용할 수도 있고, 라이브러리를 다운받아 import할 수도 있다.

jasypt와 jasypt-spring31 두개를 편한 방법으로 프로젝트에 적용하면 된다.

<!-- https://mvnrepository.com/artifact/org.jasypt/jasypt -->
<dependency>
    <groupId>org.jasypt</groupId>
    <artifactId>jasypt</artifactId>
    <version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jasypt/jasypt-spring31 -->
<dependency>
    <groupId>org.jasypt</groupId>
    <artifactId>jasypt-spring31</artifactId>
    <version>1.9.2</version>
</dependency>

Jasypt를 이용하여 암호화 및 프로퍼티 적용

일단 Jasypt를 통해서 프로퍼티를 암호화하려면, 암호화 도구가 필요하다.
위 라이브러리로 코드를 짜서 암호화도 가능하지만 더 간단한 방법이 있다.

https://github.com/jasypt/jasypt

위 사이트에 접속해서 jasypt 1.9.3을 다운 받는다.

다운받고 나면 bin 폴더 밑에 encrypt.bat, encrypt.sh가 있는데 PC 환경에 따라 실행을 한 후에 암호화를 시작한다.

https://www.devglan.com/online-tools/jasypt-online-encryption-decryption <- 이 사이트에서도 암호화가 가능하다.

$ ./encrypt.sh input="This is my message to be encrypted" password=MYPAS_WORD

 ----ENVIRONMENT-----------------

Runtime: Sun Microsystems Inc. Java HotSpot(TM) Client VM 1.6.0_03-b05



 ----ARGUMENTS-------------------

input: This is my message to be encrypted
password: MYPAS_WORD



 ----OUTPUT----------------------

k1AwOd5XuW4VfPQtEXEdVlMnaNn19hivMbn1G4JQgq/jArjtKqryXksYX4Hl6A0e

쉘파일을 실행하면서 input, password를 인자로 주면 암호화가된다.
뒤에 알고리즘도 설정할 수 있는데 아무것도 설정하지 않으면 PBEWithMD5AndDES가 기본이다.

password 값은 복호화 할때도 사용되는 값이니, 기억해두자.

이렇게 암호화가 된 값을 이제 properties 파일에 적용하자.

#예제 프로퍼티 파일
test.key=ENC(k1AwOd5XuW4VfPQtEXEdVlMnaNn19hivMbn1G4JQgq/jArjtKqryXksYX4Hl6A0e)
test.noKey=1234

암호화가 되어있는 프로퍼티 값은 복호화 대상으로 잡기위해 앞에 ENC()를 붙인다.
참고로 복호화가 필요없으면 평문으로 하면된다.

여기까지 되었으면 암호화 및 프로퍼티 준비가 완료되었다.

Spring context.xml 을 활용하여 프로퍼티 복호화

스프링 설정은 xml을 활용하는 방법이나, java로 만드는 방법이 있다.
현재 프로젝트는 xml로 되어있어서 xml 기반으로 설명을 하겠다.

복호화에는 총 3가지 설정이 필요하다.

  1. 복호화를 위한 Password와 알고리즘 설정
  2. properties 파일 불러오기 및 복호화
  3. 복호화된 값 사용하기

1. 복호화를 위한 Password와 알고리즘 설정

 <bean id="environmentVariablesConfiguration"
     class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
   <property name="algorithm" value="PBEWithMD5AndDES" />
   <property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
   <!--<property name="password" value="APP_ENCRYPTION_PASSWORD" />-->
 </bean>

위 설정은 알고리즘과 password를 설정한다.
여기서 passwordEnvName은 환경변수에 password값을 가져오는 기능으로 password의 값을 WAS가 아닌 서버환경에서 가져오기 때문에 보안이 더욱 뛰어나다.

2. properties 파일 불러오기 및 복호화

 <bean id="configurationEncryptor"
     class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
   <property name="config" ref="environmentVariablesConfiguration" />
 </bean>
 
  <bean id="propertyConfigurer"
     class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
   <constructor-arg ref="configurationEncryptor" />
   <property name="locations">
     <list>
       <value>/WEB-INF/classes/application.properties</value>
     </list>
   </property>
 </bean>

위 설정을 통해서 /WEB-INF/classes/application.properties 경로의 프로퍼티를 불러온다.
참고로 혹시라도 스프링 설정에서 다른 porperty를 불러오는 설정이 있다면 에러가 발생하기에 확인해야한다. ex) PropertyPlaceholderConfigurer

우리 프로젝트의 경우 이미 사용되고 있는 PropertyPlaceholderConfigurer 설정이 있어서 해당 설정을 주석처리하고 EncryptablePropertyPlaceholderConfigurer만 사용하게 하였다.

3. 복호화된 값 사용하기

대부분 DB연결이 주목적으로 가이드가 많이 되어있는데, 이번 프로젝트의 경우에는 다른용도로 사용이 필요했기에, bean을 하나 만들어서 사용하였다.

<beans:bean class="test.com.kmsRequestDTO">
	<beans:property name="key" value="${test.key}"/>
    <beans:property name="noKey" value="${test.noKey}"/>
</beans:bean>

이렇게 만들어놓고 필요할 때 @Autowired로 주입해서 사용하면 된다.

Jasypt 1.9.3 에러, 버그, 이슈

이번 프로젝트에서 제일 화나게 했던 내용이다. Jasypt는 현재 1.9.3 버전을 마지막으로 업데이트가 되어있다. 그래서 1.9.3으로 개발을 진행하던 중 가져온 설정파일의 value 값이 공백으로 계속 들어오는 이슈가 있었다.

당연히 스프링 설정을 잘못한줄 알고 몇시간을 고생을 하였는데, 혹시나 해서 Jasypt 1.9.3을 디버깅해보니 소스에 오류가 있었다. 라이브러리를 잘못받았는지 사용을 잘못해서 그런지는 모르겠지만, 라이브러리를 안까봤으면 화병이 날뻔 했다.

문제의 원인은 Decrypt할 때 사용되는 StandardPBEByteEncryptor의 Decrypt 함수이다.

//문제의 1.9.3 decrypt 소스
System.arraycopy(encryptedMessageKernel, encMesKernelStart, finalEncryptedMessageKernel, 0, encMesKernelSize);

위 소스는 encryptedMessageKernel배열을 encMesKernelStart 위치부터 finalEncryptedMessageKernel에 복사하는 코드이다.
그런데 encMesKernelStart의 값이 encryptedMessageKernel의 길이와 동일한 값이다.

그래서 finalEncryptedMessageKernel로 복사되는 값이 공백이 되어버렸다.

그래서 1.9.2로 다운그레이드를 해보니 위 문제되는 소스가 없었고, 정상적으로 값이 나왔다.

결론 : Jasypt는 1.9.2 버전을 사용하기를 바란다.

profile
개발을 좋아하는 마음과 다양한 경험을 토대로 좋은 개발자가 되고자 노력합니다.

0개의 댓글