2024년 10월 2일

코딩 - Spring Boot 환경에서 설정 정보 암호화

"Config Server 을 구성할 필요가 없는 경우 주요한 설정을 어떻게 암호화를 할 것인가"

Spring Boot 에서 Config Server를 사용하지 않고도 암호화를 적용하는 방법은 여러 가지가 있다. 특히, 민감한 데이터를 보호하기 위해 Jasypt 와 같은 라이브러리를 사용하여 암호화를 적용, 애플리케이션의 설정 파일이나 환경 변수에 저장된 비밀번호, API 키 등의 민감한 정보를 안전하게 암호화할 수 있다. 

◼︎ 환경

  • Model : MacBook Pro (14-inch, 2021)
  • CPU : Apple M1 Pro
  • MENORY : 16GB
  • DISK : 512 GB SSD
  • OS : macOS 13.2.4 (22F66)
  • TOOLS : Visual Studio Code, Java 11, Gradle, Docker
  • Version Control : GitHub
  • Programming Language : Java
  • Back-End Framework : Spring Boot 2.7.12, Spring Security 5.7.7 
  • DBMS : MySql 8.0.33
  • Cloud : OCI (free tier account

Jasypt ?

Jasypt (Java Simplified Encryption) 는 자바 애플리케이션 속성 파일, 데이터베이스 비밀번호, 또는 기타 중요한 데이터를 쉽게 암호화하고 복호화할 수 있도록 도와주는 것이다. Jasypt는 복잡한 암호화 알고리즘을 이해하거나 구현할 필요 없이 간단한 API를 통해 보안을 향상시킬 수 있도록 설계되었다.

주요 특징

  1. 암호화 및 복호화 기능: 비밀번호, 속성 값 등의 중요한 데이터를 쉽게 암호화하고, 필요한 시점에 복호화
  2. 구성 파일 보호: 애플리케이션의 application.properties 또는 application.yml과 같은 설정 파일에서 중요한 정보(예: 데이터베이스 연결 정보)를 암호화
  3. 알고리즘 지원: AES, DES, PBE 등 다양한 암호화 알고리즘을 지원
  4. 설정이 용이: 환경 변수나 명령줄 인자를 통해 암호화 키를 전달하고, 자동으로 암호화된 데이터를 복호화할 수 있는 기능을 제공
  5. 스프링 통합: 스프링 프레임워크와 통합되어 스프링 부트 (Spring Boot) 애플리케이션에서 손쉽게 사용

Jasypt는 특히 애플리케이션 보안 향상을 위해 중요한 정보를 암호화하는 데 유용하며, 자바 기반 프로젝트에서 많이 사용된다. 


Jasypt를 사용한 암호화 적용 방법

재십트(jasypt) 는 스프링 부트 (Spring Boot) 와의 통합을 돕기 위해 jasypt-spring-boot-starter 라이브러리를 제공한다. 이를 사용하면 Spring Boot 의 환경 설정 파일(application.properties, application.yml)에서 암호화된 값을 쉽게 처리할 수 있다.  아래는 gradle 기반 스프링 부트 (Spring Boot) 프로젝트에 재십트(jasypt) 암호화를 적용하는 것을 설명한다.

❶ 의존성 추가: build.gradle 에 jasypt-spring-boot-starter 라이브러리 의존성을 추가한다.


implementation "com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4"

❷ 암호화된 값 사용: 애플리케이션의 application.properties 또는 application.yml 파일에 민감한 데이터를 암호화된 상태로 저장할 수 있다. 암호화된 값은 ENC(...) 형식으로 표기한다.

application.yml


datasource:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:postgresql://localhost:5432/studio_db
username: ENC(amX5KdNShNl7jMYsHfpWccYeGhDWHD9bXsxXQSZGuUI=)
password: ENC(4EyexAjWphLdRG6NaDaPb2S2c6gU8PZr/QgLM7e4nY4=)

❸ Jasypt Encryptor 설정: 재십트(jasypt) 가 암호화된 값을 복호화할 수 있도록 JasyptStringEncryptor 를 설정해야 한다.  스프링 부트 (Spring Boot) 애플리케이션에서는 암호화를 위한 비밀번호를 설정하는 것으로 간단하게 구현할 수 있다.

비밀번호를 전달하는 방법은 여러가지 방법이 있다.

  1. 환경변수로 전달
  2. CI/CD 도구에서 지원하는 시크릿 관리 기능을 사용하여 전달
  3. AWS Secrets Manager, HashiCorp Vault, Azure Key Vault 등의 비밀 관리 서비스 사용하여 전달
  4. 사용자 정의 JasyptStringEncryptor 을 구현하여 원하는 곳에서 비밀번호를 로드하여 직접 사용
아래는 환경변수를 사용하여 비밀번호를 전달하는 방법이다.

application.yml

jasypt:
encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD} # 환경 변수로 암호화 비밀번호 설정


JASYPT_ENCRYPTOR_PASSWORD 환경변수에 비밀번호를 세팅.

Linux/macOS:

export JASYPT_ENCRYPTOR_PASSWORD=your-encryption-password
./gradlew bootRun

Windows:

set JASYPT_ENCRYPTOR_PASSWORD=your-encryption-password
gradlew bootRun

❹ 암호화 : Jasypt CLI(Command Line Interface)를 사용하여 값을 암호화하거나 복호화할 수 있다. 예를 들어, 다음과 같이 명령어를 사용하여 값을 암호화할 수 있다.

encrypt input="yourSecretValue" password="your-encryption-password"

jasypt 1.9.3 (binaries and javadocs)

암호화된 값을 ❷ 암호화된 값 사용 과 같이 application.yml 설정에 기술하면 된다.

재십트(jasypt) 암호화

재십트(jasypt) 에서 디폴트로 적용되는 암호화 알고리즘과 관련된 주요 값들은 다음과 같다. 이 값들은 재십트(jasypt)를 기본 설정으로 사용할 때 적용되는 값 들이다.


① 디폴트 암호화 알고리즘 
  • PBEWithMD5AndDES: 기본적으로 Jasypt는 PBE (Password-Based Encryption) 알고리즘 중 하나인 PBEWithMD5AndDES를 사용한다. PBEWithMD5AndDES는 MD5 해시 알고리즘과 DES(Data Encryption Standard)를 사용한 암호화 알고리즘이다.
  • 이 알고리즘은 기본적인 보안성을 제공하지만, 현대적 암호화 표준에 비해 상대적으로 약한 것으로 간주되기 때문에 더 강력한 알고리즘을 사용할 수 있도록 설정을 변경하는 것이 좋다.

② 디폴트 해시 알고리즘 
  • MD5재십트(jasypt)는 기본적으로 MD5 해시 알고리즘을 사용하여 암호화 키를 처리한다. MD5는 널리 사용되지만, 충돌 공격에 취약하다는 보안 문제로 인해 요즘은 SHA-256 또는 SHA-512와 같은 더 강력한 해시 알고리즘이 선호된다.

③ 키 생성 반복 횟수
  • 1000번 반복: Jasypt는 기본적으로 암호화 키를 생성할 때 1000번의 반복을 수행한다. 이 값은 비밀번호 기반 암호화의 보안성을 높이기 위한 중요한 요소로 이 값을 더 높여 보안을 강화할 수 있다.

④ 디폴트 Salt Generation (솔트 생성)
  • 랜덤 솔트: 재십트(jasypt)는 암호화 시 자동으로 랜덤 솔트(Salt) 값을 생성한다. 솔트는 암호화된 값의 보안성을 높이기 위해 추가되는 값으로, 암호화된 텍스트의 패턴화를 방지하는 역할을 한다.

⑤ 디폴트 출력 포맷 
  • Base64: 재십트(jasypt)는 암호화된 텍스트를 기본적으로 Base64 로 인코딩하여 출력한다. Base64는 바이너리 데이터를 텍스트로 인코딩하는 방식으로, 암호화된 값을 쉽게 문자열로 표현할 수 있게 한다.

⑥ IV(Initialization Vector, 초기화 벡터) 
  • 기본적으로 Jasypt는 PBEWithMD5AndDES 알고리즘을 사용할 때 초기화 벡터(IV)를 생성하지 않는데 알고리즘 자체가 IV를 사용하지 않기 때문이다. 그러나 다른 알고리즘, 예를 들어 AES와 같은 알고리즘을 사용할 때는 IV가 자동으로 처리된다. 

⑦ 디폴트 암호화기(PBE String Encryptor) 
  • 재십트(jasypt)는 기본적으로 **StandardPBEStringEncryptor**를 사용하여 문자열을 암호화 및 복호화한다.

이와 같은 기본 설정들은 애플리케이션의 보안 요구에 맞게 조정할 수 있으며, 기본값을 사용하더라도 어느 정도의 보안을 제공하지만, 더 강력한 알고리즘 변경 권장된다. 

아래는 보안 수준에 따른 알고리즘 및 설정 값을 정리한 것이다. 운영 환경이라면 최소 중간 수준이상의 알고리즘 적용이 필요하다.

  • 낮은 보안 수준
    • 알고리즘 : PBEWithMD5AndDES
    • 키 획득 반복 횟수 : 1000
    • 키 길이 : 56
    • 솔트 사용 : ✓
    • IV 사용 : ✗
    • 설명 : 기본 Jasypt 설정. MD5와 DES를 사용하는 알고리즘으로 비교적 낮은 보안 수준. 과거에 널리 사용되었으나 현대의 공격에 취약.
    • 권장 사용 환경 : 테스트 환경 또는 민감하지 않은 데이터를 암호화할 때.
  • 보통 보안 수준
    • 알고리즘 : PBEWithSHA1AndDESede
    • 키 획득 반복 횟수 : 1000
    • 키 길이 : 168
    • 솔트 사용 : ✓
    • IV 사용 : ✗
    • 설명 : SHA-1 해시 알고리즘과 3DES 암호화 알고리즘 사용. DES보다 더 안전하지만, SHA-1이 약해져 더 강력한 알고리즘이 권장됨.
    • 권장 사용 환경 : 테스트 환경 또는 민감하지 않은 데이터를 암호화할 때.
  • 중간 보안 수준
    • 알고리즘 : PBEWithSHA256And128BitAES-CBC-BC
    • 키 획득 반복 횟수 : 1000
    • 키 길이 : 168
    • 솔트 사용 : ✓
    • IV 사용 : ✓
    • 설명 : SHA-256 해시 알고리즘과 AES-128 비트 암호화를 사용. AES는 고성능과 높은 보안성을 제공. IV를 사용하여 보안성을 강화.
    • 권장 사용 환경 : 내부 시스템의 암호화 작업이나 중요하지만 최고 수준의 보안을 요구하지 않는 환경.
  • 높은 보안 수준
    • 알고리즘 : PBEWithHMACSHA512AndAES_256
    • 키 획득 반복 횟수 : 1000
    • 키 길이 : 256
    • 솔트 사용 : ✓
    • IV 사용 : ✓
    • 설명 : HMAC-SHA512 해시 알고리즘과 AES-256 비트 암호화를 사용. AES-256은 강력한 보안을 제공하며, HMAC을 사용해 무결성 보장.
    • 권장 사용 환경 : 금융 서비스, 헬스케어 시스템 등 민감한 데이터를 보호해야 하는 환경.
  • 매우높은  보안 수준
    • 알고리즘 : PBEWithHMACSHA512AndAES_256
    • 키 획득 반복 횟수 : 5000~10000
    • 키 길이 : 256
    • 솔트 사용 : ✓
    • IV 사용 : ✓
    • 설명 : 암호화와 해시에서 최고 수준의 보안. 반복 횟수를 늘리고 AES-256을 사용하여 비밀번호 기반 암호화의 보안을 최대한 강화.
    • 권장 사용 환경 : 금융 서비스, 헬스케어 시스템 등 민감한 데이터를 보호해야 하는 환경.
  • 최고  보안 수준
    • 알고리즘 : PBKDF2WithHmacSHA512 + AES_256
    • 키 획득 반복 횟수 : 10000~50000
    • 키 길이 : 256
    • 솔트 사용 : ✓
    • IV 사용 : ✓
    • 설명 : PBKDF2는 비밀번호 기반 키 도출 기능으로 반복 횟수와 HMAC-SHA512를 사용해 높은 보안성을 제공. AES-256과 함께 사용하면 최상의 보안을 제공.
    • 권장 사용 환경 : 정부, 군사 시스템, 민감한 데이터를 보호하는 최고 수준의 보안이 요구되는 환경

중간 보안 요구 이상에서는 AES-256과 함께 PBEWithHMACSHA512AndAES_256 또는 PBKDF2WithHmacSHA512를 사용하는 것이 권장. AES-256은 현재 가장 안전한 암호화 표준 중 하나이며, HMAC-SHA512는 암호화 데이터의 무결성을 보장. 반복 횟수(Iterations)를 5000번 이상으로 설정하여 암호화 키 도출 과정의 보안을 더욱 강화하는 것을 권장.

특히 개인정보와 같은 민감한 데이터 보호가 필요한 환경에서는 AES-256HMAC-SHA512를 사용한 설정을 적극 추천.

중간 수준이상의 암호화 적용

테스트 환경에서는 디폴트 암호화 알고리즘 이외의 암호화를 사용하려는 경우 오류가 발생하여 진행이 불가 하였다. 이런 이유로 환경 이슈에 독립적으로 동작하도록 보니캐슬(Bouncy Castle) 암호화 프로바이터를 사용하였다. (맥 환경이 문제는 아닌가 추정만 하였다.)

❶ 의존성 추가: build.gradle 에 보니캐슬(Bouncy Castle) 라이브러리 의존성을 추가한다.

❷ 재십트(jasypt) 에 보니캐슬(Bouncy Castle) 설정 

Jasypt 설정 예시 (AES 256 사용):

application.yml

encryptor:
password: ${JASYPT_ENCRYPTOR_PASSWORD} # 환경 변수로 암호화 비밀번호 설정
algorithm: "PBEWithSHA256And256BitAES-CBC-BC" # Bouncy Castle 알고리즘 사용
providerName: "BC" # Bouncy Castle 프로바이더 지정
key-obtention-iterations: 1000
pool-size: 1
salt-generator-classname: "org.jasypt.salt.RandomSaltGenerator"
string-output-type: "base64"


PBEWithSHA256And256BitAES-CBC-BC: 보니캐슬(Bouncy Castle)이 제공하는 AES-256 알고리즘이다.

❸ Bouncy Castle 프로바이더 등록
Java 환경에서 보니캐슬(Bouncy Castle)을 암호화 프로바이더로 등록해야 하며, 이 작업은 JVM이 시작될 때 수행할 수 있다. 스프링 부트 (Spring Boot) 에서는 Application.java 에 추가하여 프로바이터를 등록할 수 있다.


import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
SpringApplication.run(MyApplication.class, args);
}
}



좀더 자동화된 방법을 고민하다 재십트(jasypt) 라이브러리가 추가되어 있고 보니캐슬(Bouncy Castle) 암호화 라이브러리가 있는경우 보니캐슬(Bouncy Castle) 프로파이더를 추가 하고  디폴트 암호화(StandardPBEStringEncryptor) 모듈을 생성하도록 자동화된 설정을 구현하여 사용하였다.

다만 이경우 Jasypt CLI(Command Line Interface)를 사용하여 값을 암호화하거나 복호화 하는 것이 어려워저 추가로 암호화를 위한 RESTful API 을 추가하여 사용할 수 있도록 하였다.

특정 값을 암호화하려면 아래와 같이 curl 을 사용하여 암호화하고 yml 파일에 ENC() 함수를 사용하여 암호화된 값으로 설정을 추가하면 된다.

curl localhost:8080/data/encrypt -s -d 암호화할 데이터 


댓글 없음:

댓글 쓰기