0. ์ ํ์ํ๊ฐ
์ธ๋ถ API๋ DB, ๋ฏธ๋ค์จ์ด ์ฐ๋์ ์ํด์๋ ํ์ฉ์ ์ํด ์ฝ์ํ secret-key๋ฅผ ๋ค๊ณ ์์ด์ผ ํ๋ค. ๋ณดํต ๊ฐ๋ฐ์๋ค์ ์ค์ ํ์ผ์ ๊ทธ๊ฒ์ ๋ชฐ์๋ฃ๊ณ , @Value()
๋ฅผ ํ์ฉํ์ฌ ๊ทธ๊ฒ๋ค์ ๋ถ๋ฌ์จ๋ค. ๋ค์ ์ฌ์ง๊ณผ ๊ฐ์ด ๋ง์ด๋ค.
์ด๋ฐ secret-key๋ค์ ์ ์ถ๋๋ฉด ํดํน ๋ฑ ํ๋ก์ ํธ์ ์น๋ช
์ ์ธ ์ํ์ ์ค๋ค. ๊ทธ๋์ ๊ฐ๋ฐ์๋ค์ ํญ์ ์ด๊ฒ๋ค์ ๋ํด ์ ๊ฒฝ ์ฐ๊ณ , ์ธํ๋ผ ํ ๋ํ Jenkins๋ DockerHub์ ํค ๋ฆฌ์คํธ๋ค์ ๋ฐ๋ก ๊ด๋ฆฌํด์ผ ํด์ ๊ณจ์น ์ํ๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Java์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Jasypt
๋ฅผ ํ์ฉํ๋ค.
1. Jasypt๋?
(0) ์ ์
๋จ๋ฐฉํฅ ์ํธํ ํน์ ๋จ์ผ ํค ์๋ฐฉํฅ ์ํธํ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ฐ์ ์ด๋ผ ํ๋ค๋ฉด Jasypt๋ก ์ํธํํ ๋์์ ํน์ ํ์ฌ ์๋ฒ ์คํ ์ ์๋ ๋ณตํธํ ์์ผ์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค. ์ด๊ฒ์ ์ด๋ ํ ์๋ฆฌ๋ก ๊ฐ๋ฅํ ๊น?
(1) ์๋ฆฌ
- 0๏ธโฃ Secret-key ์ํธํ๋ ๊ฐ๋ฐ์๋ค์ด ๋ฏธ๋ฆฌ ๋ค ํด๋๋๋ค๊ณ ๊ฐ์
- 1๏ธโฃ ENC( ) ์์ ์ํธํ๋ Key๋ฅผ ์ง์ด๋ฃ๋๋ค.
- 2๏ธโฃ ์๋ฒ ์คํ ์ ์ค์ ํ์ผ์์ 'ENC('๋ก ์์๋๋ ๋ฌธ์์ด์ ์ฐพ๋๋ค.
- 3๏ธโฃ ํด๋น ๋ฌธ์์ด์ ์ฐพ์ผ๋ฉด Jasypt์์ ๋ง๋ ์ํธํ ๋ฌธ์์ด์ด๋ผ ํ๋จํ๊ณ ๋ณตํธํ๋ฅผ ์งํํ๋ค.
- 4๏ธโฃ ์ดํ ๋ณตํธํ๋ API Key๋ฅผ ์๋ฒ ๋ด์์ ํ์ฉ ๊ฐ๋ฅ ํ๋ค.
2. Jasypt config ์ค์
(1) ์์กด์ฑ ์ฝ์ & secret-key ์ค์ ํ์ผ์ ์์ฑ
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5'
jasypt:
encryptor:
password: spot-secret-key
secret-key๋ ์ค์ ํ์ผ์ ์ ํ๋ฉด ์๋๋ ๊ฑฐ ์๋๊ฐ์? ๐ญ
๊ทธ๊ฒ๋ ๋ง๋ค. jasypt๋ฅผ ์ํ secret-key๋ ๋ ธ์ถ๋๋ฉด ์๋๋ค. ์ฐ๋ฆฌ๋ ํจ์จ์ฑ ์ธก๋ฉด์ ๋ฐ์ ธ๋ด์ผ ํ๋ค. API KEY ์ฌ๋ฌ ๊ฐ์ ๋ํ ์ ์ถ ๋ฐฉ์ง๋ณด๋ค jasypt์ ์ฐ์ด๋ secret-key ํ๋๋ง ์ ์ถ์ ๋ํด ์ ๊ฒฝ ์ฐ๋ ๊ฒ ๊ฐ๋ฐ์ ์ ์ฅ์์๋ ๋จธ๋ฆฌ๋ฅผ ๋น์ธ ์ ์๋ค. ์ฌ๊ณผ๋ฅผ ๋ดํฌ ์์ด ์์ผ๋ก ๋์ด ์๊ณ ์ด๋ํ๋ ๊ฑฐ๋ ์ฌ๊ณผ ํ๋๋ฅผ ๋จน์ผ๋ฉด์ ์์ง์ด๋ ๊ฒ์๋ ํฐ ์ฐจ์ด๊ฐ ์๋ค.
(2) Config ํ์ผ ์ค์
@Configuration
public class JasyptConfig {
@Value("${jasypt.encryptor.password}")
private String key;
@Bean(name = "jasyptEncryptor")
public StringEncryptor stringEncryptor () {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(key); // ์ํธํ์ ์ฐ์ผ ํค
config.setAlgorithm("PBEWithMD5AndDES");// ์ํธํ ์๊ณ ๋ฆฌ์ฆ - ์๋ฐฉํฅ ๊ฐ์ธ ํค ์๊ณ ๋ฆฌ์ฆ์ ์จ์ผ ํฉ๋๋ค.
config.setKeyObtentionIterations("1000"); // ํค ๋์ถ ๋งค์๋ ๋ฐ๋ณตํ์
config.setPoolSize("1"); // ์ํธํ ์ฐ์ฐ ์ํ ์ ์ธ์คํด์ค ํ ํฌ๊ธฐ
config.setProviderName("SunJCE"); // ์ฌ์ฉํ ๋ณด์ ์ ๊ณต์ ์ค์
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); // ์ํธ ๋ฐฉ์: ๋์ผํ ๊ฐ์ด ์ํธํ๋๋ฉด ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค๋๋ก ํ๊ธฐ
config.setStringOutputType("base64"); // ์ํธํ๋ ๋ฌธ์์ด์ ์ถ๋ ฅ ๋ฐฉ์
encryptor.setConfig(config);
return encryptor;
}
}
์ด๋ ๊ฒ config ํ์ผ์ ์ค์ ํ๋ฉด, ์ด์ ์๋ฒ๋ฅผ ์คํํ ๋๋ง๋ค, ์ค์ ํ์ผ์ ์๋ "ENC("๋ก ์์ํ๋ ๋ฌธ์์ด์ ์ฐพ์์ ์ค์ ์ ๊ธฐ๋ก๋ key์ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ณตํธํ๋ฅผ ํ๋ค.
3. ๊ทธ๋ฌ๋ฉด ์ํธํ๋ ์ด๋ป๊ฒ ํจ?
๋ํผ๋ฐ์ค๋ฅผ ์ฐพ์๋ดค์ง๋ง, ์๋ ์ํธํ์ ๋ํ ์ค๋ช ์ ์ฐพ์๋ณด๊ธฐ ํ๋ค๋ค. ๋ค๋ค ๊ฐ๋ฐ์๊ฐ ์์๋ก ํ๋ ๋ฏ ํ๋ค. ์๋ ์ํธํ ๋ฐฉ๋ฒ์ ๋ํด์ ์ฐพ์๋ดค์ง๋ง GPT ๋ง์ ๊ฐ๋ฐ์๊ฐ ์ง์ ํด์ผํ๋ค๋ ๋ต๋ณ์ ๋ด๋์๋ค. ๋ฐ๋ผ์
- 1๏ธโฃ ์ํธํ ๋งค์๋๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด ์๋ฒ ๋ด๋ถ์์ secret-key ์ต์ด ๋ฐ๊ธ ์ ์ฌ์ฉ ํ๊ฑฐ๋
- 2๏ธโฃ ์ํธํ ์ฌ์ดํธ๋ฅผ ํ์ฉํด์ผ ํ ๋ฏ ํ๋ค.
https://www.devglan.com/online-tools/jasypt-online-encryption-decryption
4. ํ ์คํธ ์ฝ๋ ์์ฑ
ํ์๋ ํ์๋ค์ด ์ธ ์ ์๋๋ก ํ
์คํธ ์ฝ๋๋ฅผ ํ์ฉํด ๊ฐ๋ฐ์๋ฅผ ์ํ ์์ ์ํธํ ์๋น์ค
๋ฅผ ๋ง๋ค์๋ค.
(1) ํด๋ ๊ตฌ์กฐ
(2) JasyptUtil
package spot.spot.global.security.util;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class JasyptUtil {
private final StringEncryptor stringEncryptor;
@Autowired
public JasyptUtil(@Qualifier("jasyptEncryptor") StringEncryptor stringEncryptor) {
this.stringEncryptor = stringEncryptor;
}
/*
* ๋ฌธ์์ด์ Jasypt๋ก ์ํธํ ํ๋ ๋งค์๋
* @Param plain Text (String) ์ํธํํ ๋ฌธ์์ด
* @return ENC(์ํธํ๋ ๋ฌธ์์ด)
* */
public String encrypt(String str) {
return "ENC (" + stringEncryptor.encrypt(str)+ ")";
}
}
spring container์ Bean์ผ๋ก ๋ฑ๋ก๋ Encryptor ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ ๊ทธ๊ฒ์ ํ์ฉํด ์ธ์๋ก ๋ฐ์ ๋ฌธ์์ด์ ์ํธํ ํ๋ ์ฝ๋์ด๋ค.
(3) Test ํด๋์ ํ ์คํธ ์ฝ๋ ํ๊ฒฝ ๋ง๋ค๊ธฐ
resource๊ฐ ๋ ํ์ํ ์ด์ ๋ Test ํด๋ ๋ด๋ถ์ ํ์ผ๋ค์ main์ ์๋ ์ค์ ํ์ผ์ ์ฐธ์กฐํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ด์ฉ๋ฌผ์ ๋๊ฐ๋ค. ์ด์ ์์์ ๋ง๋ util์ ํ์ฉํด ๋จ์ ํ ์คํธ๋ก ์ํธํ๋ ๋ฌธ์์ด์ ๋ฐ์ ์ ์๋ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์.
package spot.spot.global.security.config;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import spot.spot.global.security.util.JasyptUtil;
@SpringBootTest
public class IssueEncryptString {
@Value("${jasypt.encryptor.password}")
private String key;
private JasyptUtil jasyptUtil;
@BeforeEach
void setUp() {
// ์ํธํ๋ฅผ ๋ด๋นํ๋ ์ํธํ ๊ฐ์ฒด ์ค์
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(key);
config.setAlgorithm("PBEWithMD5AndDES");
encryptor.setConfig(config);
jasyptUtil = new JasyptUtil(encryptor);
}
@Test
@DisplayName("1. YAML์์ ๊ฐ์ ธ์จ ํค๋ก ์ํธํ/๋ณตํธํ ํ
์คํธ")
void testEncryptionDecryption() {
String str = "MySecretData";
// ์ํธํ ๋ฐ ๋ณตํธํ ์ํ
String encryptedText = jasyptUtil.encrypt(str);
System.out.println(encryptedText);
}
}
์ด๋ฅผ ์คํ ํ๋ฉด,
์ ๋์จ๋ค.
5. ์ด๋ฒ ํ๋ก์ ํธ์ ํ์ฉ ํ๋๊ฐ..?
์ด๋ฒ ํ๋ก์ ํธ์์๋ ํ์ฉํ์ง ์๊ธฐ๋ก ํ๋ค. ์๋ํ๋ฉด ํด๋ผ์ฐ๋ ์ ๋ฌธ๊ฐ๊ฐ ํ์ ๊ณ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ๋์ ์ ์ธํ๋ผํ์์ API๋ฅผ ํตํด ํค๋ฅผ ๋์ ์ผ๋ก ์๋ฒ์ ๊ณต๊ธํด์ฃผ๋ valut๋ฅผ ํ์ฉํ ์๋น์ค ์ํคํ
์ฒ๋ฅผ ์ค๊ณ ๋ฐ ๊ตฌํํ ์์ ์ด๋ค.
์ด๋ฅผ ํ์ฉํ์ฌ ์๋ฒ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฒ์ ๋ค์ ์ฃผ์ ํฌ์คํ
ํ๊ฒ ๋ค.
VALUT API ํ์ฉ ์ํคํ ์ฒ