Spring Boot์ application.yml(.properties)๊ณผ ๊ฐ์ ์ค์ ์ ๋ณด ํ์ผ์๋ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ ๋ณด๋ API ํค, ๋น๋ฐ๋ฒํธ์ ๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์ค์ ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด๋ฌํ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ํ๋ฌธ์ผ๋ก ์ค์ ํ๊ฒ ๋๋ฉด ๊ฐํน ์ ๋ณด๊ฐ ๋
ธ์ถ๋์์ ๋ ์ฌ๊ฐํ ๋ฌธ์ ๋ฅผ ์ด๋ ํ ์ ์๋ค. Jasypt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ดํ๋ฆฌ์ผ์ด์
์ ์ค์ ์ ๋ณด๋ฅผ ์ํธํํ์ฌ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ๋ณดํธํ ์ ์๋ค. ๊ฐ๋จํ ์์ ์ฝ๋์ ํจ๊ป spring์์ Jasypt ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์ ๋ฆฌํด ๋ณด๊ณ ์ ํ๋ค.
Jasypt for Spring boot
Jasypt๋ Spring boot 2.X ๋ฒ์ ๊ณผ 3.X ๋ฒ์ ๊ณผ ํตํฉ์ ์ง์ํ๋ค. ์์ธํ ๋ฌธ์๋ jasypt-spring-boot git์ ์ฐธ๊ณ ํ๊ธฐ ๋ฐ๋๋ค.
ํ๋ก์ ํธ์ jasypt-spring-boot์ ํตํฉํ๋ ๋ฐฉ๋ฒ์๋ 3๊ฐ์ง๊ฐ ์๋ค.
- @SpringbootApplication ํน์ @EnableAutoConfiguration ์ด๋ ธํ ์ด์ ์ ์ง์ ํ๋ ๊ฒฝ์ฐ jasypt-spring-boot-starter ๋ํ๋์๋ง ์ถ๊ฐํ๋ฉด ์ ์ฒด spring environment์์ ์ํธํ ๊ฐ๋ฅํ ์์ฑ์ ํ์ฑํ ํ ์ ์๋ค.
- jasypt-spring-boot(jasypt-spring-boot-starter ์๋) ๋ํ๋์๋ฅผ ์ถ๊ฐํ๊ณ @Configuration ํด๋์ค์ @EnableEncryptableProperties ์ด๋ ธํ ์ด์ ์ ์ถ๊ฐํ์ฌ ์ ์ฒด spring environment์์ ์ํธํ ๊ฐ๋ฅํ ์์ฑ์ ํ์ฑํ ํ ์ ์๋ค.
- jasypt-spring-boot ๋ํ๋์๋ฅผ ์ถ๊ฐํ๊ณ ๊ฐ๋ณ ์ํธํ ๊ฐ๋ฅํ ํ๋กํผํฐ ์์ค๋ฅผ @EncryptablePropertySource์ ์ง์ ํ์ฌ ํน์ ์ค์ ํ์ผ์ ๋ํด์ ์ํธํ ๊ฐ๋ฅํ ์์ฑ์ ํ์ฑํ ํ ์ ์๋ค.
jasypt-spring-boot-starter ๋ํ๋์๋ฅผ ์ถ๊ฐํ๋ฉด ์๋์ผ๋ก jasypt-spring-boot ๋ํ๋์๊ฐ ์ถ๊ฐ๋๋ค.
jasypt for spring boot dependency
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>XML@SpringBootApplication ํน์ @EnableAutoConfiguration ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ ๋ํ๋์๋ฅผ ์ถ๊ฐํ๋ฉด ๋ชจ๋ ์์คํ
์์ฑ, ํ๊ฒฝ ์์ฑ, ๋ช
๋ น์ค ์ธ์, application.properties, application-*.properties[.yml] ์ ์์ฑ์ ์ํธํ๋ ์์ฑ์ ํฌํจํ ์ ์๋ค.
@SpringBootApplication ํน์ @EnableAutoConfiguration ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ ์๋ ๋ํ๋์๋ฅผ ์ถ๊ฐํ๊ณ @Configuration ํด๋์ค์ @EnableEncryptableProperties ์ด๋
ธํ
์ด์
์ ์ง์ ํ์ฌ ๋ชจ๋ ์์คํ
์์ฑ, ํ๊ฒฝ ์์ฑ, ๋ช
๋ น์ค ์ธ์, application.properties, application-*.properties[.yml] ์ ์์ฑ์ ์ํธํ๋ ์์ฑ์ ํฌํจํ ์ ์๋ค.
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>3.0.5</version>
</dependency>XML@Configuration
@EnableEncryptableProperties
public class MyApplication {
...
}Java@SpringBootApplication ํน์ @EnableAutoConfiguration ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ง ์๊ณ ํน์ ์์ฑ ํ์ผ์ ๋ํด์๋ง ์ํธํ๋ ์์ฑ์ ํ์ฑํ ํ๋ ค๋ฉด ์๋์ ๊ฐ์ด ์ค์ ํ๋ค.
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>3.0.5</version>
</dependency>XML@Configuration
@EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
public class MyApplication {
...
}Javaencrypted.properties ํ์ผ์ ๋ํด์๋ง ์ํธํ๋ ์์ฑ์ ์ค์ ํ ์ ์๋๋ก ํ๋ค.
๋น๋ฐ๋ฒํธ ๊ธฐ๋ฐ์ ์ํธํ ์ค์ ๊ตฌ์ฑ
Jasypt๋ ๋น๋ฐ๋ฒํธ ๊ธฐ๋ฐ์ ์ํธํ๋ฅผ ๊ตฌ์ฑํด์ผ ํ๋ค. jasypt ์ํธํ๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ๊ธฐ๋ณธ ์ค์ ์ ์๋์ ๊ฐ๋ค.
| Key | Required | Default Value |
|---|---|---|
| jasypt.encryptor.password | True | – |
| jasypt.encryptor.algorithm | False | PBEWITHHMACSHA512ANDAES_256 |
| jasypt.encryptor.key-obtention-iterations | False | 1000 |
| jasypt.encryptor.pool-size | False | 1 |
| jasypt.encryptor.provider-name | False | SunJCE |
| jasypt.encryptor.provider-class-name | False | null |
| jasypt.encryptor.salt-generator-classname | False | org.jasypt.salt.RandomSaltGenerator |
| jasypt.encryptor.iv-generator-classname | False | org.jasypt.iv.RandomIvGenerator |
| jasypt.encryptor.string-output-type | False | base64 |
| jasypt.encryptor.proxy-property-sources | False | false |
| jasypt.encryptor.skip-property-sources | False | empty list |
jasypt.encryptor.password ํญ๋ชฉ๋ง ํ์์ด๊ณ ๋๋จธ์ง ์ค์ ํญ๋ชฉ์ ๋ชจ๋ ์ต์ ์ด๋ค. ์ค์ ์ ๋ณด๋ฅผ ์ํธํํ์ฌ ์ฌ์ฉํ๊ธฐ ์ํ ์ฉ๋๋ก๋ password ํญ๋ชฉ๋ง ์ค์ ํ๊ณ ๋๋จธ์ง๋ ๊ทธ๋ฅ ๋ํดํธ๋ก ์ฌ์ฉํด๋ ์ถฉ๋ถํ ๊ฒ ๊ฐ๋ค.
๋ํดํธ encryptor ์ฌ์ฉ
@SpringBootApplication ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ Auto Configuration์ด ์ ์ฉ๋์ด StringEncryptor ๋น์ ์๋ ์ฃผ์ ๋ฐ์ ์ฌ์ฉํ ์ ์๋ค. StringEncryptor ๋ ์ธํฐํ์ด์ค์ด๊ณ ๊ตฌํ์ฒด ํด๋์ค๋ ์๋์ ๊ฐ๋ค.

๋ํดํธ StringEncryptor๋ DefaultLazyEncryptor ์ด๊ณ jasypt.encryptor.password ๊ฐ ์ค์ ๋์ด ์์ด์ผ ํ๋ค.
์๋๋ ๋ํดํธ StringEncryptor๋ฅผ ์ฌ์ฉํ ํ
์คํธ ์ฝ๋์ด๋ค.
package com.example.jpa.jasypt;
import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
import org.assertj.core.api.Assertions;
import org.jasypt.encryption.StringEncryptor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
//@EnableAutoConfiguration ์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ
//@EnableEncryptableProperties annotation ์ ํตํด์ default encryptor ๋ฅผ ์ฃผ์
๋ฐ์ ์ ์๋ค.
@EnableEncryptableProperties
//๋ด๋ถ์ ์ผ๋ก @ConfigurationProperties๋ฅผ ํตํด์ ์ค์ ์ ๋ณด๋ฅผ ๋ก๋ ํ๋ฏ๋ก ํ
์คํธ์์๋
//์๋ ์ด๋
ธํ
์ด์
์ ์ง์ ํด ์ค์ผ ํ๋ค.
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
public class DefaultJasyptTest {
@Autowired
private StringEncryptor stringEncryptor;
@Test
void default_jasypt_test() {
String encrypted = stringEncryptor.encrypt("test");
System.out.println("encrypted: " + encrypted);
String decrypted = stringEncryptor.decrypt(encrypted);
System.out.println("decrypted: " + decrypted);
Assertions.assertThat(decrypted).isEqualTo("test");
}
}Javajasypt.encryptor.password ์ค์ ์ ์๋์ ๊ฐ๋ค. (application.yml)
jasypt:
encryptor:
password: "test-password"YAMLCustom Encryptor ์ฌ์ฉ
@Configuration ํด๋์ค์์ StringEncryptor ๋น์ ์ ์ํ์ฌ ์์ฑํ ์ ์์ผ๋ฉฐ ๊ธฐ๋ณธ Encryptor๋ ๋ฌด์๋๋ค.
package com.example.jpa.config;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JasyptConfig {
@Bean("jasyptEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
//์๋ณตํธํ์ ์ฌ์ฉ๋ ๋น๋ฐ๋ฒํธ ์ค์ (ํ์)
config.setPassword("test-password");
//์๋ ์ค์ ์ ๋ชจ๋ ์ต์
(๋ํดํธ๋ก ์
ํ
ํจ)
config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}Java1.5 ๋ฒ์ ๋ถํฐ Bean์ ์ด๋ฆ์ ํ์๋ก ์ง์ ํ๊ณ jasypt.encryptor.bean=<๋น์ด๋ฆ>๊ณผ ๊ฐ์ด ์ค์ ํด์ผ ํ๋ค.
@Bean ์ด๋ฆ์ ์ง์ ํ์ง ์์ผ๋ฉด default ๋ก ๋น ์ด๋ฆ์ jasyptStringEncryptor๋ก ์ค์ ๋๋ค.
jasyptStringEncryptor ์ด๋ฆ์ด ์๋ ๋ค๋ฅธ ์ด๋ฆ์ ์ง์ ํ ๊ฒฝ์ฐ์๋ jasypt.encryptor.bean=<๋น์ด๋ฆ> ์ ์ค์ ํด์ผ ํ๋ค.
application.yml ์ค์ ์ ์๋์ ๊ฐ๋ค.
jasypt:
encryptor:
bean: jasyptEncryptorYAML์ ์ํ์ฝ๋์ ์ง์ ๋ StringEncryptor ๋น์ ์ฌ์ฉํ๋ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ์ฌ ํ ์คํธ ํด๋ณด์๋ค.
package com.example.jpa.jasypt;
import com.example.jpa.config.JasyptConfig;
import org.assertj.core.api.Assertions;
import org.jasypt.encryption.StringEncryptor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = JasyptConfig.class)
public class CustomEncryptorTest {
@Autowired
private StringEncryptor jasyptEncryptor;
@Test
void custom_jasypt_test() {
String encrypted = jasyptEncryptor.encrypt("test");
System.out.println("encrypted: " + encrypted);
String decrypted = jasyptEncryptor.decrypt(encrypted);
System.out.println("decrypted: " + decrypted);
Assertions.assertThat(decrypted).isEqualTo("test");
}
}JavaJasyptConfig์ ์ ์๋ StringEncryptor ๋น์ PooledPBEStringEncryptor ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. ์ ํ ์คํธ ์ฝ๋์์ ์ฃผ์ ๋ฐ์ StringEncryptor ํด๋์ค์ ๊ฐ์ฒด๋ PooledPBEStringEncryptor ์์ ํ์ธํ ์ ์๋ค.

์ ํ ์คํธ ์ฝ๋์์ ์ํธํ๋ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
encrypted: vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBvPlaintext๋ณตํธํ ์ฒ๋ฆฌ ํ ์คํธ
jasypt ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ํธํ๋ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํ๋๋ฐ ์ฌ์ฉ๋๋ prefix์ suffix ๋ ๊ฐ๊ฐ “ENC(“์ “)” ์ด๋ค.
์ฆ, field: ENC(์ํธํ๋ฐ์ดํฐ)์ ๊ฐ์ด ์ค์ ํ๋ค.
์ ํ
์คํธ ์ฝ๋๋ฅผ ํตํด์ ์ํธํ๋ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํ์ ์๋์ผ๋ก ๋ณตํธํ ์ฒ๋ฆฌ๊ฐ ๋๋์ง ํ์ธํด ๋ณด์.
์ฐ์ application.yml ํ์ผ์ ์ํธํ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํ๋ค.
encrypted:
data: ENC(vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv)YAML์ ์ค์ ์ ‘test’ ๋ฌธ์์ด์ ์ํธํํ ๋ฐ์ดํฐ๋ฅผ ์ค์ ํ ๊ฒ์ด๋ค.
์๋๋ encrypted.data ์ค์ ์ @Value ์ด๋
ธํ
์ด์
์ผ๋ก decryptedData ๋ณ์์ ํ ๋นํ๊ณ ํ์ธํ๋ ํ
์คํธ ์ฝ๋์ด๋ค.
package com.example.jpa.jasypt;
import com.example.jpa.config.JasyptConfig;
import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
initializers = ConfigDataApplicationContextInitializer.class,
classes = JasyptConfig.class)
//@SpringBootApplication ํน์ @EnableAutoConfiguration์ ์ฌ์ฉํ๋
//production ์ฝ๋์์๋ ์๋ ์ด๋
ธํ
์ด์
์ ์ง์ ํ ํ์๋ ์๋ค.
@EnableEncryptableProperties
public class ReadJasyptConfigTest {
@Value("${encrypted.data}")
private String decryptedData;
@Test
void decryption_config_test() {
Assertions.assertThat(decryptedData).isEqualTo("test");
System.out.println("decrypted config: " + decryptedData);
}
}Java์ ํ
์คํธ ์ฝ๋์์ @SpringBootApplication ์ด๋
ธํ
์ด์
ํน์ @EnableAutoConfiguration ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ๋ production ์ฝ๋์์๋ @EnableEncryptableProperties ์ด๋
ธํ
์ด์
์ ์ง์ ํ ํ์๋ ์๋ค.
์ ํ
์คํธ ์ฝ๋์ ์ํ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
[main] INFO com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesBeanFactoryPostProcessor -- Post-processing PropertySource instances
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Skipping PropertySource configurationProperties [class org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Converting PropertySource test [org.springframework.core.env.MapPropertySource] to EncryptableMapPropertySourceWrapper
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Converting PropertySource systemProperties [org.springframework.core.env.PropertiesPropertySource] to EncryptableMapPropertySourceWrapper
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Converting PropertySource systemEnvironment [org.springframework.core.env.SystemEnvironmentPropertySource] to EncryptableSystemEnvironmentPropertySourceWrapper
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Converting PropertySource random [org.springframework.boot.env.RandomValuePropertySource] to EncryptablePropertySourceWrapper
[main] INFO com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter -- Converting PropertySource Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' [org.springframework.boot.env.OriginTrackedMapPropertySource] to EncryptableMapPropertySourceWrapper
[main] INFO com.ulisesbocchio.jasyptspringboot.filter.DefaultLazyPropertyFilter -- Property Filter custom Bean not found with name 'encryptablePropertyFilter'. Initializing Default Property Filter
[main] INFO com.ulisesbocchio.jasyptspringboot.resolver.DefaultLazyPropertyResolver -- Property Resolver custom Bean not found with name 'encryptablePropertyResolver'. Initializing Default Property Resolver
[main] INFO com.ulisesbocchio.jasyptspringboot.detector.DefaultLazyPropertyDetector -- Property Detector custom Bean not found with name 'encryptablePropertyDetector'. Initializing Default Property Detector
[main] INFO com.ulisesbocchio.jasyptspringboot.encryptor.DefaultLazyEncryptor -- Found Custom Encryptor Bean org.jasypt.encryption.pbe.PooledPBEStringEncryptor@22fba58c with name: jasyptEncryptor
decrypted config: testPlaintext์ํธํ ์ค์ ํ์ ๋ณ๊ฒฝํ๊ธฐ
Jasypt์์ ์ํธํ ์ค์ ํ์์ ‘ENC(์ํธํ๋ฐ์ดํฐ)’ ์ด๋ค. ์ด ํ์์ custom ํ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.
์ค์ ์ผ๋ก ๋ณ๊ฒฝ
jasypt.encryptor.property.prefix, jasypt.encryptor.property.suffix ์ค์ ์ ํตํด์ ์ํธํ ์ค์ ํ๋ ๊ฐ ํ์์ ์ ์ํ ์ ์๋ค.
jasypt:
encryptor:
property:
prefix: "ENC@["
suffix: "]"
bean: jasyptEncryptor
encrypted:
data: ENC@[vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv]YAML์์ ๊ฐ์ด ์ค์ ํ ReadJasyptConfigTest ๋ฅผ ์ํํ๋ฉด ์ ์์ ์ผ๋ก ๋ณตํธํ ๋จ์ ์ ์ ์๋ค.
๋ง์ฝ ์ค์ ์ ์๋์ ๊ฐ์ด ์ค์ ํ๋ค๋ฉด
jasypt:
encryptor:
property:
prefix: "ENC@["
suffix: "]"
bean: jasyptEncryptor
encrypted:
data: ENC(vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv)YAMLReadJasyptConfigTest ์ํ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค.
org.opentest4j.AssertionFailedError:
expected: "test"
but was: "ENC(vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv)"
Expected :"test"
Actual :"ENC(vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv)"Plaintext์ฆ encrypted.data ์ ์ค์ ๊ฐ ENC(…)๋ฅผ ์ํธํ๋ ๋ฐ์ดํฐ๋ก ์ ๋๋ก ์ธ์ํ์ง ๋ชปํ๊ฒ ๋๋ค.
EncryptablePropertyDetector ๋น ์์ฑ์ผ๋ก ๋ณ๊ฒฝ
EncryptablePropertyDetector ๋ฅผ ๊ตฌํํ ๋น์ ์ ์ํ์ฌ ์ํธํ ์ค์ ํ์์ ๋ณ๊ฒฝํ ์ ์๋ค. ์ด ๋ Bean ์ด๋ฆ์ encryptablePropertyDetector ๋ก ์ง์ ํ๊ณ , ๋ง์ฝ encryptablePropertyDetector๊ฐ ์๋ ๋ค๋ฅธ ์ด๋ฆ์ผ๋ก ์ง์ ํ๋ ๊ฒฝ์ฐ์๋
jasypt.encryptor.property.detector-bean: <๋น ์ด๋ฆ> ์ ๊ฐ์ด ๋น ์ด๋ฆ์ ์ค์ ํด์ผ ํ๋ค. StringEncryptor ๋น์ ์์ฑํ๋ ๊ฒฝ์ฐ์๋ jasypt.encryptor.bean์ ์ค์ ํด์ผ ํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋ฐฉ์์ธ๋ฐ ์ด๋ ์๋ ํด๋์ค์ ๊ด๋ จ์ด ์๋ค.
@Configuration
public class EncryptablePropertyResolverConfiguration {
private static final String ENCRYPTOR_BEAN_PROPERTY = "jasypt.encryptor.bean";
private static final String ENCRYPTOR_BEAN_PLACEHOLDER = String.format("${%s:jasyptStringEncryptor}", ENCRYPTOR_BEAN_PROPERTY);
private static final String DETECTOR_BEAN_PROPERTY = "jasypt.encryptor.property.detector-bean";
private static final String DETECTOR_BEAN_PLACEHOLDER = String.format("${%s:encryptablePropertyDetector}", DETECTOR_BEAN_PROPERTY);
private static final String RESOLVER_BEAN_PROPERTY = "jasypt.encryptor.property.resolver-bean";
private static final String RESOLVER_BEAN_PLACEHOLDER = String.format("${%s:encryptablePropertyResolver}", RESOLVER_BEAN_PROPERTY);
private static final String FILTER_BEAN_PROPERTY = "jasypt.encryptor.property.filter-bean";
private static final String FILTER_BEAN_PLACEHOLDER = String.format("${%s:encryptablePropertyFilter}", FILTER_BEAN_PROPERTY);
private static final String ENCRYPTOR_BEAN_NAME = "lazyJasyptStringEncryptor";
private static final String DETECTOR_BEAN_NAME = "lazyEncryptablePropertyDetector";
private static final String CONFIG_SINGLETON = "configPropsSingleton";
/** Constant <code>RESOLVER_BEAN_NAME="lazyEncryptablePropertyResolver"</code> */
public static final String RESOLVER_BEAN_NAME = "lazyEncryptablePropertyResolver";
/** Constant <code>FILTER_BEAN_NAME="lazyEncryptablePropertyFilter"</code> */
public static final String FILTER_BEAN_NAME = "lazyEncryptablePropertyFilter";
...
...
...
}JavaEncryptablePropertyDetector๋ฅผ implement ํ ๋น์ ์์ฑํ๋ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
package com.example.jpa.config;
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyDetector;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Optional;
@Configuration
public class JasyptConfig {
@Bean("jasyptEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
//์๋ณตํธํ์ ์ฌ์ฉ๋ ๋น๋ฐ๋ฒํธ ์ค์ (ํ์)
config.setPassword("test-password");
//์๋ ์ค์ ์ ๋ชจ๋ ์ต์
(๋ํดํธ๋ก ์
ํ
ํจ)
config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
@Bean(name = "customDetector")
public EncryptablePropertyDetector customDetector() {
return new CustomEncryptablePropertyDetector();
}
private static class CustomEncryptablePropertyDetector implements EncryptablePropertyDetector {
private static final String prefix = "ENC@[";
private static final String suffix = "]";
@Override
public boolean isEncrypted(String property) {
if (property == null) {
return false;
}
final String trimmedValue = property.trim();
return (trimmedValue.startsWith(prefix) &&
trimmedValue.endsWith(suffix));
}
@Override
public String unwrapEncryptedValue(String property) {
return Optional.ofNullable(property)
.map(value -> value.substring(
prefix.length(),
(value.length() - suffix.length())))
.orElse("");
}
}
}JavacustomDetector ์ด๋ฆ์ ๋น์ ์ ์ํ์๋ค. customDetector ๋น์ ์ค์ ํ๋์ ์ํธํ ํ์์ธ์ง ์ฌ๋ถ๋ฅผ ์ฐพ๋๋ฐ ์ฌ์ฉ๋์๋ DefaultPropertyDetector๋ฅผ ๋์ ํ์ฌ ์ฌ์ฉ๋๋ค. isEncrypted ๋ ์ค์ ๊ฐ์ด ์ํธํ ํ์์ด ๋ง๋์ง ์ฌ๋ถ๋ฅผ ์ฒดํฌํ๋ ๋ฉ์๋์ด๊ณ unwrapEncryptedValue ๋ prefix, suffix ๋ฅผ ์ ์ธํ ์ํธํ๋ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ์ฌ ๋ฆฌํดํ๋ ๋ฉ์๋์ด๋ค.
application.yml ์ค์ ์ ์๋์ ๊ฐ๋ค.
jasypt:
encryptor:
property:
detector-bean: customDetector
bean: jasyptEncryptor
encrypted:
data: ENC@[vwOUi946+YovW0IRw/O4ePs8JMpx/bhPGge+mnqVQP5W1VgNK9lCcE2s6YoWrdBv]YAMLJasypt ํ๋กํผํฐ ๋ณตํธํ ๋์ ๋ฐฉ์
@EnableAutoConfiguration ์ด๋
ธํ
์ด์
์ด ์ง์ ๋ ๊ฒฝ์ฐ ์๋์ผ๋ก JasyptSpringBootAutoConfiguration ํด๋์ค๊ฐ ์ฃผ์
๋๋ฉฐ ํด๋น Configuration์ @Import(EnableEncryptablePropertiesConfiguration.class) ๋ฅผ Import ํ๋๋ฐ EnableEncryptablePropertiesConfiguration ํด๋์ค๋ EncrytablePropertyResolverConfiguration ํด๋์ค๋ฅผ Import ํ๋ค.
EncryptablePropertyResolverConfiguration ํด๋์ค๋ EncryptablePropertySourceConverter ๋น๊ณผ ์ฌ์ฉ์ ์ ์ StringEncryptor ๋น๊ณผ ๊ด๋ จ๋ ๋น์ ์์ฑํ๋ค. EncryptablePropertySourceConverter ๋น์ BeanFactoryPostProcessor๋ฅผ ๊ตฌํํ EnableEncryptablePropertiesBeanFactoryPostProcessor ๋น์ ์ฃผ์
๋๋ค.
EnableEncryptablePropertiesBeanFactoryPostProcessor๋ postProcessBeanFactory ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ฉฐ ํด๋น ๋ฉ์๋ ์์์ PropertySource ๊ฐ์ฒด ํ์
์ EncryptableMapPropertySourceWrapper ํ์
์ผ๋ก convert๋ฅผ ํ๊ณ EncryptableMapPropertySourceWrapper๋ฅผ ํตํด์ ์ฌ์ฉ์๊ฐ ์์ฑํ StringEncryptor ๋น ํน์ ๋ํดํธ StringEncryptor ๋น์ ํตํด์ ๋ณตํธํ ์ฒ๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง๋ค.
์๋๋ Jasypt ์ JasyptSpringBootAutoConfiguration ํด๋์ค ๋ด์ฉ์ด๋ค.
/**
* <p>JasyptSpringBootAutoConfiguration class.</p>
*
* @author Ulises Bocchio
* @version $Id: $Id
*/
@Configuration
@Import(EnableEncryptablePropertiesConfiguration.class)
public class JasyptSpringBootAutoConfiguration {
}Java์๋๋ EnableEncryptablePropertiesConfiguration ํด๋์ค ๋ด์ฉ์ด๋ค.
@Configuration
@Import({EncryptablePropertyResolverConfiguration.class, CachingConfiguration.class})
@Slf4j
public class EnableEncryptablePropertiesConfiguration {
/**
* <p>enableEncryptablePropertySourcesPostProcessor.</p>
*
* @param environment a {@link org.springframework.core.env.ConfigurableEnvironment} object
* @param converter a {@link com.ulisesbocchio.jasyptspringboot.EncryptablePropertySourceConverter} object
* @return a {@link com.ulisesbocchio.jasyptspringboot.configuration.EnableEncryptablePropertiesBeanFactoryPostProcessor} object
*/
@Bean
public static EnableEncryptablePropertiesBeanFactoryPostProcessor enableEncryptablePropertySourcesPostProcessor(final ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
return new EnableEncryptablePropertiesBeanFactoryPostProcessor(environment, converter);
}
}Java์ Configuration ํ์ผ์์ BeanFactoryPostProcessor๋ฅผ ๊ตฌํํ EnableEncryptablePropertiesBeanFactoryPostProcessor ๋น์ ์์ฑํ๋ ๊ฒ์ ์ ์ ์๋ค.
@EnableEncryptableProperties ์ด๋
ธํ
์ด์
์ญ์ @Import(EnableEncryptablePropertiesConfiguration.class) ๋ฅผ Import ํ์ฌ ์ ์ค๋ช
๊ณผ ๋์ผํ ๋ก์ง์ผ๋ก ์ํธํ ๋ ์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ณตํธํ๋ฅผ ์งํํ๊ฒ ๋๋ค.
์ด๋ ๋ณตํธํ์ ์ฌ์ฉ๋๋ StringEncryptor ๋ Configuration ์ผ๋ก ์์ฑํ StringEncryptor ๋น์ด ๋ณตํธํ๋ฅผ ์ํํ๊ฒ ๋๋ค.
์๋๋ @EnableEncryptableProperties ์ด๋
ธํ
์ด์
ํ์ผ ๋ด์ฉ์ด๋ค.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(EnableEncryptablePropertiesConfiguration.class)
public @interface EnableEncryptableProperties {
}Java์ง๊ธ๊น์ง Spring์์ jasypt-spring-boot์ ์ด์ฉํ์ฌ config ๋ฐ์ดํฐ๋ฅผ ์ํธํํ์ฌ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์์ ๋ณด์๋ค. jasypt-spring-boot์ github ๋ฌธ์์๋ ๋ ๋ง์ ๋ด์ฉ์ด ์์ง๋ง ์ฌ๊ธฐ๊น์ง๋ง ํด๋ ์ถฉ๋ถํ๋ค๊ณ ์๊ฐํ๋ค.
์ฐธ๊ณ ๋งํฌ
https://github.com/ulisesbocchio/jasypt-spring-boot</a >
http://www.jasypt.org/