애플리케이션의 데이터베이스 비밀번호나 API 키와 같은 민감한 정보를 평문으로 저장하면, 누구나 접근할 수 있어 보안상 위험하다.
GitHub의 공개 레포지토리에 업로드하기 위해 Jasypt를 활용하여 민감한 정보들을 암호화했는데, 그 과정을 작성해보고자 한다.
0. Jasypt란?
Jasypt(Java Simplified Encryption)는 Java 애플리케이션에서 간편하게 추가할 수 있는 암호화 라이브러리다.
특히, 애플리케이션의 설정 파일이나 환경 변수 등에 포함된 민감한 정보를 암호화하여 보호하는 데 유용하다.
1. Jasypt 라이브러리 추가
build.gradle에 jasypt 의존성을 추가한다.
build.gradle
dependencies {
// jasypt - 데이터 암호화 라이브러리
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'
}
2. Jasypt 설정 파일 추가
jasypt의 암호화 설정 파일을 추가한다.
JasyptConfig.java
@Configuration
@EnableEncryptableProperties
public class JasyptConfig {
@Value("${jasypt.encryptor.password}") // 환경변수에 저장된 jasypt.encryptor.password 값을 가져와서 사용할 것
private String password;
@Bean("jasyptStringEncryptor") // Bean 이름 설정 - jasyptStringEncryptor
public StringEncryptor stringEncryptor() {
// PooledPBEStringEncryptor 클래스 : 비밀번호 기반 암호화(PBE)를 사용하여 문자열을 암/복호화
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
// SimpleStringPBEConfig 클래스 : 암호화 설정
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(password); // 암호화 비밀번호
config.setAlgorithm("PBEWithMD5AndTripleDES"); // 암호화 알고리즘
config.setKeyObtentionIterations("1000"); // 키 생성 반복 횟수 설정
config.setPoolSize("1"); // 인스턴스 풀 사이즈
config.setProviderName("SunJCE"); // 암호화 서비스 제공자 설정
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); // 솔트 생성기 설정 - org.jasypt.salt.RandomSaltGenerator 클래스
config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator"); // 초기화 벡터(IV) 생성기 - "org.jasypt.iv.RandomIvGenerator" 클래스
config.setStringOutputType("base64"); // 암호화된 데이터 출력 형식 - base64
encryptor.setConfig(config); // encryptor에 설정 저장
return encryptor;
}
}
1. 암호화 비밀번호를 담을 변수 password를 선언한다.
암호화 비밀번호는 환경변수로 저장된 값을 @Value
어노테이션으로 값을 가져온다.
환경변수에 값을 저장하는 방법은 후술한다.
2. 암호화 인코더를 설정한다.
Jasypt Spring Boot의 Readme(링크)를 참고하여 작성한다.
설정 내용 자세히 보기(더보기 클릭)
PooledPBEStringEncryptor
- 비밀번호 기반 암호화(PBE, Password-Based Encryption)를 수행한다. PBE는 비밀번호를 기반으로 데이터를 암호화하고 복호화하는 방법이다.
- "Pooled"은 이 클래스가 여러 암호화 작업을 동시에 처리할 수 있는 풀(pool)을 관리한다는 것을 의미한다. 이는 대량의 암호화/복호화 연산을 빠르게 처리할 수 있게 해준다.
SimpleStringPBEConfig
- 암호화 설정 클래스이다.
setPassword(password)
- 암호화와 복호화에 사용될 비밀번호를 설정한다
setAlgorithm("PBEWithMD5AndTripleDES")
- 암호화에 사용될 알고리즘을 지정한다.
setKeyObtentionIterations("1000")
- 키 생성 과정에서 사용될 반복 횟수를 지정한다.
- 반복 횟수가 높아질수록 오래 걸리지만 보안은 강력해진다.
setPoolSize("1")
- 동시에 처리할 수 있는 암호화 작업의 수를 지정한다.
setProviderName("SunJCE")
- 암호화 서비스를 제공하는 제공자를 지정한다.
- 기본값인 SunJCE를 사용하였다.
setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator")
- 솔트 생성기를 지정한다.
- 솔트는 같은 데이터를 암호화해도 매번 다른 결과를 생성하여 보안을 강화한다.
- 기본값인 org.jasypt.salt.RandomSaltGenerator를 사용하였다.
setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator")
- 초기화 벡터(IV) 생성기를 지정한다.
- IV는 암호화 블록 체인 모드에서 첫 번째 블록을 암호화할 때 사용되며, 같은 데이터를 암호화해도 매번 다른 결과를 생성하여 보안을 강화한다.
- 기본값인 org.jasypt.iv.RandomIvGenerator를 사용하였다.
setStringOutputType("base64")
- 암호화된 데이터의 출력 형식을 지정한다.
- 기본값인 base64를 사용하였으며, Base64는 바이너리 데이터를 텍스트 형식으로 인코딩하는 방법이다.
encryptor.setConfig(config)
- 앞서 설정한 config 객체를 encryptor에 적용한다.
return encryptor
- 설정이 완료된 encryptor 객체를 반환한다.
- 이 객체는 이후 데이터의 암호화와 복호화에 사용된다.
3. 환경변수에 암호화 비밀번호 추가
인텔리제이 상단의 실행 환경에서 구성 편집을 클릭한다.
실행 환경의 VM 옵션에 비밀번호를 설정한다.
(VM 옵션 칸이 보이지 않으면 옵션 수정 > VM 옵션 추가를 클릭한다.)
-Djasypt.encryptor.password=비밀번호입력
4. 암호화 하기
✅온라인 사이트 이용하기
https://www.devglan.com/online-tools/jasypt-online-encryption-decryption
Programming Blog Article Feeds as per your Interest | DevGlan
Best programming article feeds as per your Interest on different technologies. Subscribe to any technology and explore the best articles from around the web.
www.devglan.com
위의 사이트에서 텍스트와 비밀번호를 입력해 암/복호화 값을 간편하게 얻을 수 있다.
사이트 사용법이 어렵지 않고, 나는 테스트 코드를 작성해 암호화하는 방법을 선택했으므로 사용법은 기술하지 않고 넘어가도록 하겠다.
✅암호화 테스트 코드 작성하기
테스트 코드 작성에 앞서 build.gradle에 다음 코드를 추가해, 테스트 환경에서 암호화 비밀번호를 가져올 수 있게 한다.
build.gradle
test {
systemProperty "jasypt.encryptor.password", System.getProperties().get("jasypt.encryptor.password")
}
jasypt가 제대로 작동하는지 확인하는 테스트 코드를 작성한다.
src/test/java 하위 패키지에 테스트 클래스를 생성하고 아래와 같이 작성한다.
JasyptConfigTest.java
@SpringBootTest
class JasyptConfigTest {
@Autowired
@Qualifier("jasyptStringEncryptor")
private StringEncryptor encryptor;
@Test
@DisplayName("Jasypt 암/복호화 테스트")
public void testJasypt() {
String value = "암호화할 텍스트";
String encrypted = encryptor.encrypt(value);
String decrypted = encryptor.decrypt(encrypted);
System.out.println("encrypted : " + encrypted + " / decrypted : " + decrypted);
assertThat(decrypted).isEqualTo(value);
}
}
텍스트를 암호화하고 다시 복호화하여 콘솔에 출력하고, 원본 텍스트와 복호화한 텍스트가 일치하는지 확인한다.
테스트가 잘 통과되었다😊
5. 암호화된 텍스트로 yml 파일 내용 교체
yml의 설정값 중 보안이 필요한 텍스트를 교체한다.
예를 들면 데이터베이스 연결 정보를 아래와 같이 작성할텐데,
spring:
datasource:
url: databaseUrl
username: user
password: 1234
이러한 민감한 정보들을 공개적으로 게시하기 전에, 앞서 작성한 Jasypt 테스트 파일로 암호화한 값으로 대체한다.
테스트 후 콘솔창에 출력된 encrypted 뒷부분을 복사해, 다음과 같은 형식으로 입력해준다.
ENC(암호화 완료된 값)
그럼 암호화된 값으로 교체된 yml 파일은 아래와 같은 형식이 될 것이다.
spring:
datasource:
url: ENC(gPWgbopLm/dcIOC4YmXHEsVkkX5ER/M/zwNp9dimUzIsIjf9RXGing==)
username: ENC(gPWgbopLm/dcIOC4YmXHEsVkkX5ER/M/zwNp9dimUzIsIjf9RXGing==)
password: ENC(gPWgbopLm/dcIOC4YmXHEsVkkX5ER/M/zwNp9dimUzIsIjf9RXGing==)
암호화된 값으로 바꿔주었으므로 GitHub 등에 공개적으로 게시할 수 있게 되었다😊
참고자료
https://github.com/ulisesbocchio/jasypt-spring-boot?tab=readme-ov-file