본문 바로가기
실습/리눅스 서버 + 스프링 부트

application.properties (yml) 암호화

by 이민우 2022. 7. 25.
728x90
반응형

신입사원분을 대상으로 하는 OJT 과정 중 "Spring Boot 기반 개발" 과정을 담당하게 되었다.

이에 간단한 자료와 예제 프로젝트를 작성하여 OJT를 진행하였다.

 

application.properties (yml)에 대한 설명을 하던 중 다음과 같은 질문을 받았다.

 

"저 application.properties 내 DB 정보는 외부에 유출이 되면 안될텐데, 저걸 저렇게 그대로 작성해도 괜찮나요?"

 

application.properties 내 정보는 특정 라이브러리를 사용하면 암호화할 수 있다는 것 정도는 알고 있었다. 하지만 그 라이브러리가 무엇인지, 어떻게 사용할 수 있는지는 미처 알지 못했었다. 그래서 위 질문에 제대로 된 답변을 내놓지 못했다.

 

OJT가 끝난 후 위에서 받은 질문은 언제든지 현업에서도 받을 수 있는 질문이고, 언제든 요구사항으로 들어올 수 있는 사항이라는 생각이 들었다. 그래서 구글링을 통해 방법을 찾아놓았으며, 언제든 프로젝트에 적용할 수 있도록 소스코드를 저장해놓고자 포스팅을 작성했다.

application.properties 파일에 암호화를 하기 위해 가장 먼저 해야할 작업은 pom.xml에 암호화 라이브러리를 추가하는 것이다.


pom.xml 내 dependencies에 다음 dependency를 추가한다.

<dependency>
	<groupId>com.github.ulisesbocchio</groupId>
	<artifactId>jasypt-spring-boot-starter</artifactId>
	<version>3.0.3</version>
</dependency>

 

그 후 추가한 디펜던시를 설정해준다.
방법은 아래와 같다.

 

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.jasypt.salt.RandomSaltGenerator;
import org.jasypt.salt.SaltGenerator;
import org.jasypt.salt.StringFixedSaltGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class EncryptConfig {
	
	private String encryptKey = "test-key"; // 인코딩용 키 생성
	private String fixedSalt = "test-salt";
	
	@Bean(name="StringEncryptor")
	public StringEncryptor stringEncryptor() {
		PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
		SimpleStringPBEConfig config = new SimpleStringPBEConfig();
		
		config.setPassword(encryptKey);				//암호화할 때 사용하는 키
		config.setAlgorithm("PBEWithMD5AndDES");	//암호화 알고리즘
		config.setKeyObtentionIterations(1000);		//반복할 해싱 회수
		config.setPoolSize(1); 						//인스턴스 pool
		// SALT 지정
		// 1. 랜덤 방식
		//config.setSaltGenerator(saltGenerator())
		// 2. 고정 방식
		config.setSaltGenerator(new StringFixedSaltGenerator(fixedSalt));
		config.setStringOutputType("base64"); 		// 인코딩 방식 지정
		
		encryptor.setConfig(config);
		
		return encryptor;
	}
	
	@Bean(name="SaltGenerator")
	public SaltGenerator saltGenerator() {
		return new RandomSaltGenerator();
	}

}

 

위에서 알고리즘 설정은 PBEWithMD5AndDES 외에도 여러 알고리즘이 설정 가능하다.

어떤 알고리즘이 가능한지 보는 방법은 Test 코드를 통해 아래의 코드로 확인이 가능하다.

@Test
void getAlgorithmList() {
	logger.info("@@@ DigestAlgorithms \t: {}", AlgorithmRegistry.getAllDigestAlgorithms());
	logger.info("@@@ PBEAlgorithms \t: {}", AlgorithmRegistry.getAllPBEAlgorithms());
}

 

여기까지 완료되었다면 이제 DB내 데이터들을 암호화해야 한다.


해당하는 데이터는 spring.datasource의 URL, USERNAME, PASSWORD이다.


암호화는 test 코드로 돌려서 암호화된 String을 복사하여 사용하면 되는데, 이상하게 @Autowired로 StringEncryptor를 불러오면 에러가 발생하여 다음과 같이 작성하였다.

@Test
void getEncryptDbInfo() {
	StandardPBEStringEncryptor pbeEnc = new StandardPBEStringEncryptor();
	String url="jdbc:mariadb://....:3306/....";
	String userName="....";
	String password="....";
	
	pbeEnc.setAlgorithm("PBEWithMD5AndDES"); // Encoder 설정 시와 같은 알고리즘으로 구성
	pbeEnc.setPassword("test-key"); // Encoder 설정 시와 같은 키로 구성
	pbeEnc.setSaltGenerator(new StringFixedSaltGenerator("test-salt"));
		
	logger.info("@@@url \t: {}", pbeEnc.encrypt(url));
	logger.info("@@@userName \t: {}", pbeEnc.encrypt(userName));
	logger.info("@@@password \t: {}", pbeEnc.encrypt(password));
}

 

위의 테스트 코드를 실행하면 Logger에 의해 암호화된 URL, USERNAME, PAWWSORD가 콘솔에 출력되는데, 해당 암호화된 String을 복사하여 application.yml에 ENC() 태그안에 넣어준다.

spring.datasource.url=ENC(wj....f1wUyIk)
spring.datasource.username=ENC(g4A....4=)
spring.datasource.password=ENC(QzK....A==)

 

여기까지 설정했다면 이제 프로젝트가 실행되며 암호화된 정보가 복호화되어 Spring 내부에 들어가게 된다.

 

위 과정이 정상적으로 진행된다면 JPA를 통한 CRUD가 정상적으로 이루어져야 한다.

 

테스트를 위해 id, password로 이루어진 간단한 테이블을 생성한 후 Domain, Repository 클래스를 작성하여 아래의 테스트 코드를 돌려보자.

@Autowired testRepository repo;

@Test
void dbCrud() {
	testDomain td = new testDomain("123", "456");
	repo.save(td);
		
	logger.info("@@@ SAVED");
		
	testDomain returnTd = repo.findById("123").orElse(null);
	assertEquals(returnTd.getId(), td.getId());
	logger.info("@@@ LOADED");
		
	repo.delete(td);
	logger.info("@@@ DELETED");
}

 

 

에러 없이 위의 로그들이 잘 출력된다면 성공한 것이다.

728x90
반응형

'실습 > 리눅스 서버 + 스프링 부트' 카테고리의 다른 글

[Shell Script] 쉘 스크립트 문법  (0) 2022.08.16
JPA 페이징  (0) 2022.07.25
Spring WebFlux Filter  (0) 2022.07.25
Spring Security rememberMe (자동 로그인)  (0) 2022.07.25
Ehcache  (0) 2022.04.02