Spring Boot 애플리케이션에서 DB 비밀번호, API Key 등 민감한 프로퍼티를 평문으로 application.yml에 저장하면 보안에 취약하다. **Jasypt(Java Simplified Encryption)**를 사용하면 프로퍼티 값을 암호화된 상태로 저장하고, 런타임에 자동으로 복호화하여 사용할 수 있다.
1. 의존성 추가
// build.gradle.kts
dependencies {
implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5")
}
2. Java Config 작성
@Configuration
@EnableEncryptableProperties
class JasyptConfig(
@Value("\${jasypt.encryptor.password:}") private val encryptorPassword: String
) {
@Bean("jasyptStringEncryptor")
fun stringEncryptor(): StringEncryptor {
val config = SimpleStringPBEConfig().apply {
password = encryptorPassword
algorithm = "PBEWithMD5AndDES"
poolSize = 1
stringOutputType = "base64"
setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator")
setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator")
}
return PooledPBEStringEncryptor().apply { setConfig(config) }
}
}
주요 설정:
algorithm— 암호화 알고리즘.PBEWithMD5AndDES는 가장 보편적으로 사용되는 알고리즘poolSize— 암호화 풀 크기. 멀티스레드 환경에서는 늘려주면 좋음RandomSaltGenerator— 같은 평문이라도 매번 다른 암호문이 생성됨
⚠️ jasypt.encryptor.password는 절대로 소스코드나 yml 파일에 하드코딩하지 않아야 한다. 반드시 VM 옵션이나 환경변수로 전달한다.
3. 암호문 생성
테스트 코드를 작성하여 암호문을 생성한다.
@DisplayName("JasyptConfig 암복호화 테스트")
class JasyptConfigTest {
private lateinit var encryptor: StringEncryptor
@BeforeEach
fun setUp() {
val jasyptConfig = JasyptConfig("mySecretEncKey")
encryptor = jasyptConfig.stringEncryptor()
}
@Test
@DisplayName("암호화된 문자열을 복호화하면 원문과 동일하다")
fun decrypt_shouldReturnOriginalPlainText() {
// given
val plainText = "myDatabasePassword!@#"
val encrypted = encryptor.encrypt(plainText)
// when
val decrypted = encryptor.decrypt(encrypted)
// then
println("평문: $plainText")
println("암호문: $encrypted") // ← 이 값을 ENC()에 넣어 사용
println("복호문: $decrypted")
assertThat(decrypted).isEqualTo(plainText)
}
}
테스트를 실행하면 콘솔에 암호문이 출력된다:
평문: myDatabasePassword!@#
암호문: Ckfh13n/jh2gUJ2futzT3UyE0yCNB2AQRI5riQ6bWlI=
복호문: myDatabasePassword!@#
💡 RandomSaltGenerator를 사용하므로 동일한 평문을 암호화해도 매번 다른 암호문이 생성된다. 어떤 암호문이든 같은 키로 복호화하면 원문이 복원된다.
4. application.yml에 암호문 적용
출력된 암호문을 ENC()로 감싸서 yml에 삽입한다.
# application-live.yml
spring:
datasource:
url: jdbc:mysql://my-db-host:3306/mydb
username: ENC(AYMbwzwz6yKQM/YzEKnvng==)
password: ENC(Ckfh13n/jh2gUJ2futzT3UyE0yCNB2AQRI5riQ6bWlI=)
Jasypt가 ENC() 패턴을 자동으로 감지하여 런타임에 복호화한다. 암호화하지 않은 프로퍼티는 그대로 평문으로 사용된다.
5. 암호화 키 전달
방법 1: VM 옵션
java -Djasypt.encryptor.password=mySecretEncKey -jar app.jar
방법 2: 환경변수
export JASYPT_ENCRYPTOR_PASSWORD=mySecretEncKey
jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD}
방법 3: systemd 서비스 파일 (Linux 서버 배포 시)
[Service]
ExecStart=/usr/bin/java \
-Djasypt.encryptor.password=mySecretEncKey \
-jar /opt/app/lifelog.jar
6. 적용 시 주의사항
| 항목 | 설명 |
|---|---|
| 암호화 키 관리 | 암호화 키는 소스코드에 포함하지 않으며, 배포 환경에서만 주입 |
| 키 분실 | 키를 분실하면 암호문을 복호화할 수 없으므로 안전하게 보관 |
| 알고리즘 변경 | 한번 암호화한 뒤 알고리즘을 변경하면 기존 암호문이 복호화 불가 |
| RandomSalt | 같은 평문이라도 매번 다른 암호문이 생성되므로, Git diff로 값 유출 여부를 판단할 수 없음 |
| 디버깅 | 복호화 실패 시 EncryptionOperationNotPossibleException 발생 — 키가 맞는지 먼저 확인 |
그리고, spring 하위 프로퍼티에만 이게 먹힌다. 다른 프로퍼티에 넣으면 복호화되지 않는다.
정리
Jasypt는 설정 한 번이면 이후 ENC()만 감싸주면 되므로, 가장 적은 코드로 프로퍼티 보안을 확보할 수 있는 방법이다.