깃허브를 이용한 프로젝트를 진행하거나 혹은 외부에 공개되면 안되는 정보들을 암호화 해야할 경우를 만나게 된다면 간단하게 Jasypt(Java Simplified Encryption) 를 사용하여 암호화 해보자.
위와같은 properties 설정 시, 프로젝트 내 암호화 키 등 암호화를 해야하는 경우를 만나게 된다. 위 상황이 만약 H2 환경이 아니라 실제 RDS 혹은 사용자의 비밀번호라면? Commit 시 외부에 공개되는 끔찍한 상황에 처하게 된다.
Jasypt 3.0.4 + Spring Boot 2.5.6 환경 기준에서 실행함.
공식 홈페이지는 http://www.jasypt.org/
사용자가 편하게 암호화를 도와주는 도구이다. 굉장히 편리하다.
(만약 도커를 사용하여 컨테이너 실행 시 환경변수를 사용하고싶다면 버전은 3.0.4를 필수로 사용해야한다. 3.0.3으로 한참을 시도했는데 안되다가 3.0.4버전 사용 시 잘 실행되었다.)
dependencies{implementation group: 'com.github.ulisesbocchio', name: 'jasypt-spring-boot-starter', version: '3.0.4'}
import lombok.RequiredArgsConstructor;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@RequiredArgsConstructor
@Configuration
public class JasyptConfig {
// @Value("${jasypt.encryptor.password}") 환경변수 사용 시 주석 처리된 부분 이용
// private String encryptKey;
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
// config.setPassword(encryptKey);
config.setPassword("password");
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}
jasypt.encryptor.bean=jasyptStringEncryptor
jasypt.encryptor.algorithm=PBEWithMD5AndDES
jasypt.encryptor.iv-generator-classname=org.jasypt.iv.NoIvGenerator
ENC 안에 들어갈 코드는 직접 만들 수 있고 사이트를 이용할 수 있다.
직접 만들기
위 클래스 내 혹은 test 환경에서 hello라는 텍스트를 만들어보겠다.
이해가 안된다면 아래의 test코드를 보면 더욱 잘 이해할 수 있다.
String plainText = "hello";
String encryptText = encryptor.encrypt(plaintext)
하지만 나는 중요 정보를 사이트에 요청 값으로 넘기고싶지 않기 때문에 직접 만들었다.
위에서 만든 암호화된 텍스트로 암호화 하고싶은 정보를 ENC(텍스트) 형식으로 변환한다.
spring.datasource.url=ENC(q20q+xrQ2BtdPOBY5hjjujh3WrKmx13Y7sKWc3PbQZGp8SnsxilyCjeDjo9dc4pWt9WujwVs53xQCLNpqTTPicLaNsMdHItaCfvswC8vB+900tE1elKnxLlSeuKkbQo0)
spring.datasource.username=ENC(3bxjZZEiUNZU1wuZ0VKImg==)
spring.datasource.password=ENC(Iuw7Pc5/KgqO4dTlOcDm4Sg6m2dGuRaj)
코드 실행 시 salt의 값을 Random하게 설정하여 매 번 실행시 encrypt text가 변경된다.
class JasyptTest {
@Test
public void jasypt_test() {
String plainText = "hello";
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword("password");
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
String encryptText = encryptor.encrypt(plainText);
System.out.println(encryptText);
String decryptText = encryptor.decrypt(encryptText);
System.out.println(decryptText);
assertThat(plainText).isEqualTo(decryptText);
}
}
docker run 실행시 환경변수를 지정하면 된다.
sudo docker run -it --name 컨테이너이름 -d -e password=비밀번호 -p PORT:PORT 이미지명
Dockerfile 엔트리 포인트 구성
ENTRYPOINT ["java","-jar","-Djasypt.encryptor.password=비밀번호","./Jar파일이름.jar"]
이제 더이상 키를 탈취당하지 말자