-
JWT 토큰 암호화 방식 및 키 저장 방식웹 개발 2024. 6. 26. 23:05반응형
사용자 인증시에 jwt 토큰을 많이 사용하고 있지만 어떤 구성과 어떤 역할인지는 많이 확인하였지만 직접 암호화는 방식과 암호화를 위한 키 저장 방식에 대해 스스로 모르고 있다 생각하여 정리해본다.
> JWT 토큰 생성 방식
1. 대칭 키 암호화 방식 (HMAC)
대칭 키 암호화 방식은 동일한 비밀 키를 사용하여 JWT 토큰을 생성하고 검증합니다. 주로 HS256, HS384, HS512 알고리즘이 사용됩니다. 이 방식은 설정과 사용이 간단하지만, 비밀 키가 유출될 경우 보안에 취약할 수 있습니다.
{ ... String secretKey = "your-256-bit-secret"; // JWT 생성 String jwt = Jwts.builder() .setSubject("user") .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1시간 유효 .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); // JWT 검증 Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt); System.out.println("JWT is valid"); ... }
- 대칭 키 암호화 방식을 사용한 회사
ex) 우아한형제들2. 비대칭 키 암호화 방식 (RSA 또는 ECDSA)
비대칭 키 암호화 방식은 개인 키로 서명하고 공개 키로 검증하는 방식을 사용합니다. 주로 RS256, RS384, RS512, ES256, ES384, ES512 알고리즘이 사용됩니다. 이 방식은 키를 안전하게 관리할 수 있으며, 검증 키를 공개적으로 사용할 수 있어 보안성이 높습니다.
1) RSA
- 특징: RSA는 공개키 암호화 방식 중 하나로, 두 개의 큰 소수를 기반으로 한 암호화 알고리즘입니다.
- 장점:
- 널리 사용되고 검증된 알고리즘입니다.
- 비교적 구현이 쉽고, 라이브러리 지원이 풍부합니다.
- 더 긴 키를 사용할 수 있어 보안성이 높습니다.
2) ECDSA (Elliptic Curve Digital Signature Algorithm)
- 특징: ECDSA는 타원 곡선을 기반으로 한 공개키 암호화 방식입니다.
- 장점:
- 같은 보안 수준에서 더 짧은 키 길이를 사용하여 효율적입니다.
- 빠른 키 생성과 서명, 검증 속도를 제공합니다.
- 경량 환경에서도 사용 가능하여 모바일이나 IoT 장치에서 적합합니다.
- 비대칭 키 암호화 방식을 사용한 회사
ex) 쿠팡대칭키, 비대칭키 암호 방식이란?
* 대칭키 암호화 (Symmetric-key encryption):
1. 공통 키를 사용: 암호화와 복호화에 동일한 키를 사용합니다.
2. 속도가 빠름: 대칭키 암호화는 처리 속도가 빠르기 때문에 대량의 데이터를 효율적으로 처리할 수 있습니다.
3. 키 관리가 중요: 키를 안전하게 관리해야 하며, 통신하는 모든 측이 동일한 키를 가지고 있어야 합니다.
예를 들어, AES (Advanced Encryption Standard)는 대칭키 암호화의 대표적인 예입니다.
* 비대칭키 암호화 (Asymmetric-key encryption):
1. 공개 키와 개인 키를 사용: 암호화에는 공개 키를, 복호화에는 개인 키를 사용합니다.
2. 안전성이 높음: 개인 키는 보안이 중요하며, 공개 키는 공개될 수 있습니다.
3. 처리 속도가 느림: 대칭키 암호화보다 처리 속도가 느립니다. 따라서 대칭키 암호화로 데이터를 암호화하고, 이 대칭키를 공개 키로 암호화하여 안전하게 전송하는 방법이 일반적입니다.
RSA (Rivest-Shamir-Adleman) 및 ECC (Elliptic Curve Cryptography)는 비대칭키 암호화의 대표적인 예입니다.3. 대칭 키 와 비대칭 키의 선택 기준
JWT 암호화 방식에서 대칭키 방식(HMAC)과 비대칭키 방식(RSA/ECDSA)을 선택할 때의 기준은 다음과 같은 여러 가지 요소를 고려해야 합니다.
각 방식의 장단점을 비교하고, 애플리케이션의 요구 사항에 따라 적절한 방식을 선택하는 것이 중요합니다.1) 대칭키 방식 (HMAC) 선택 기준
- 단순성:
- 구현이 간단: HMAC 방식은 설정과 사용이 상대적으로 간단합니다. 동일한 비밀 키를 사용하여 서명하고 검증하기 때문에 추가적인 공개 키 관리가 필요 없습니다.
- 성능:
- 빠른 처리 속도: HMAC 방식은 비대칭키 방식보다 계산이 단순하므로, 더 빠르게 서명 및 검증 작업을 수행할 수 있습니다. 고성능이 요구되는 환경에서 유리할 수 있습니다.
- 키 관리의 단순화:
- 단일 키 사용: 한 가지 비밀 키만 관리하면 되기 때문에, 키 관리가 단순합니다. 그러나 비밀 키가 유출되면 보안에 큰 위협이 될 수 있습니다.
- 신뢰할 수 있는 환경:
- 폐쇄된 시스템: 키를 안전하게 관리할 수 있는 신뢰할 수 있는 환경에서 사용하기 적합합니다. 예를 들어, 내부 네트워크에서만 사용하는 경우.
2) 비대칭키 방식 (RSA/ECDSA) 선택 기준
- 보안 강화:
- 보안성: 비대칭키 방식은 비밀 키(private key)와 공개 키(public key)를 사용합니다. 비밀 키는 안전하게 보호되고, 공개 키는 자유롭게 배포할 수 있어 키 유출에 대한 위험이 줄어듭니다.
- 키 분배:
- 분산 시스템: 여러 시스템 간에 키를 공유해야 하는 경우, 비대칭키 방식이 더 적합합니다. 공개 키를 공개적으로 배포하여 누구나 검증할 수 있기 때문에 키 관리가 용이합니다.
- 확장성:
- 서드파티 통합: 외부 서비스나 서드파티와 통합할 때, 공개 키를 제공하여 검증을 할 수 있도록 합니다. 이를 통해 확장성이 높아지고, 안전하게 토큰을 검증할 수 있습니다.
- 법적 및 규제 요구 사항:
- 규제 준수: 특정 산업이나 법적 요구 사항에 따라, 비대칭키 방식의 강력한 보안이 요구될 수 있습니다.
3) 암호화 방식 선택에 대한 내용 요약
- 대칭키 방식 (HMAC)
- 장점: 구현이 간단, 빠른 성능, 단일 키 관리
- 단점: 비밀 키 유출 시 보안 위협, 키 교환 어려움
- 적합한 경우: 내부 애플리케이션, 고성능 요구, 간단한 키 관리 환경
- 비대칭키 방식 (RSA/ECDSA)
- 장점: 높은 보안성, 키 분배 용이, 서드파티 통합 적합
- 단점: 상대적으로 복잡한 구현, 더 많은 계산 자원 필요
- 적합한 경우: 분산 시스템, 외부 서비스 통합, 높은 보안 요구 사항
- 결론
- 대칭키 방식과 비대칭키 방식을 선택할 때는 보안 요구 사항, 성능, 키 관리의 복잡성, 법적 및 규제 요구 사항 등을 종합적으로 고려해야 합니다.
특정 상황에 따라 적절한 방식을 선택하면 애플리케이션의 보안성과 성능을 최적화할 수 있습니다.
- 대칭키 방식과 비대칭키 방식을 선택할 때는 보안 요구 사항, 성능, 키 관리의 복잡성, 법적 및 규제 요구 사항 등을 종합적으로 고려해야 합니다.
> 키를 관리하는 KeyStore 와 KMS 가 있는데 각 역할과 목적
키스토어(KeyStore)와 KMS(Key Management Service)는 모두 암호화 키를 안전하게 관리하는 데 사용되지만, 그 역할과 기능, 사용 방식에 차이가 있습니다.
다음은 키스토어와 KMS의 비교 및 각각의 역할에 대한 설명입니다.
1. 키스토어(KeyStore)
- 역할:
- 암호화 키와 인증서를 로컬 시스템에서 안전하게 저장하고 관리.
- 자바 애플리케이션 내에서 키와 인증서를 로드하고 사용할 수 있도록 지원.
- 사용 방식:
- 주로 파일 시스템에 저장되며, 애플리케이션이 실행되는 환경 내에서 접근 가능.
- 대칭키, 비대칭키, 인증서 등을 저장할 수 있음.
- 키스토어 파일을 암호화하여 보호하며, 키를 저장할 때 비밀번호를 사용.
- 예: JKS, PKCS12 등 다양한 포맷 지원.
- 예시:
- 로컬 애플리케이션에서 SSL/TLS 통신을 설정하거나,
- JWT 서명/검증에 사용되는 키를 저장.
2. KMS(Key Management Service)
- 역할:
- 클라우드 환경에서 중앙 집중적으로 키를 관리하고 보호.
- 키 생성, 저장, 회전, 폐기 등의 라이프사이클 관리 기능 제공.
- 주요 클라우드 제공업체(AWS, Google Cloud, Azure)에서 제공하는 서비스로, 하드웨어 보안 모듈(HSM)을 사용하여 키를 보호.
- 사용 방식:
- 네트워크를 통해 API로 접근하여 키 관리 및 암호화/복호화 작업 수행.
- 키를 물리적으로 클라우드 제공업체의 인프라 내에서 안전하게 관리.
- 클라우드 리소스와의 통합이 용이하며, 정책 기반 접근 제어 가능.
- 예: AWS KMS, Google Cloud KMS, Azure Key Vault.
- 예시:
- 클라우드 애플리케이션에서 데이터 암호화, 디지털 서명, 인증서 관리 등에 사용.
- 자동 키 회전 및 모니터링 기능을 통한 강화된 보안 관리.
3. 키스토어와 KMS 비교
항목 키스토어(KeyStore) KMS (Key Management Service) 위치 로컬 파일 시스템 클라우드 인프라 관리 방식 애플리케이션 내 관리 중앙 집중적 관리 접근 방식 애플리케이션 코드에서 직접 접근 API 호출을 통한 네트워크 접근 보안 암호화된 파일로 저장 HSM을 통한 강력한 보안 확장성 로컬 환경에 한정 클라우드 환경의 확장성 기능 키 저장 및 로드, 인증서 관리 키 생성, 회전, 폐기, 정책 기반 접근 제어, 감사 로그 등 4. 결론
- 키스토어는 로컬 환경에서의 키와 인증서 관리를 위한 도구로, 주로 자바 애플리케이션에서 사용됩니다.
- KMS는 클라우드 환경에서 중앙 집중적으로 키 관리를 제공하며, 더 강력한 보안과 확장성을 제공합니다.
따라서, 로컬 환경에서 실행되는 애플리케이션의 키 관리가 필요하다면 키스토어를 사용하는 것이 적합하고, 클라우드 기반 애플리케이션에서 강력한 보안과 확장성을 필요로 한다면 KMS를 사용하는 것이 적합합니다.
> 키스토어(KeyStore) 의 종류
Java에서는 다양한 형식의 키스토어(KeyStore)를 지원합니다. 각각의 형식은 특정 용도에 맞춰 선택하여 사용할 수 있습니다. 주요한 키스토어 형식들은 다음과 같습니다:
- JKS (Java KeyStore):
- 가장 전통적이고 널리 사용되는 Java 키스토어 형식입니다.
- 기본적으로 비밀번호로 보호됩니다.
- 개인 키와 인증서를 포함할 수 있습니다.
- 확장자는 .jks입니다.
- 예: KeyStore.getInstance("JKS")
- PKCS12:
- 공개 키 암호화 표준 (PKCS #12)에 따라 개발된 형식입니다.
- 개인 키와 해당 인증서(및 체인)를 포함할 수 있습니다.
- 확장자는 .p12 또는 .pfx입니다.
- 예: KeyStore.getInstance("PKCS12")
- PKCS11:
- 하드웨어 보안 모듈(HSM)과 같은 하드웨어 장치에서 키를 관리하기 위한 표준입니다.
- 자바에서는 PKCS11 프로바이더를 통해 이 형식을 지원합니다.
- 예: KeyStore.getInstance("PKCS11")
- Windows-MY:
- Windows 운영 체제의 개인 인증서 저장소에 접근하기 위한 형식입니다.
- Windows의 기본 인증서 저장소에 접근할 때 사용됩니다.
- 예: KeyStore.getInstance("Windows-MY")
- BKS (Bouncy Castle KeyStore):
- Bouncy Castle 라이브러리에서 제공하는 키스토어 형식으로, JKS와 비슷하지만 암호화 알고리즘이 추가됩니다.
- 확장자는 .bks입니다.
- 예: KeyStore.getInstance("BKS")
- UBER (Bouncy Castle UBER KeyStore):
- Bouncy Castle 라이브러리의 또 다른 키스토어 형식으로, 여러 다른 키스토어 유형을 단일 파일에 저장할 수 있습니다.
- 확장자는 .ubr입니다.
- 예: KeyStore.getInstance("UBER")
> JKS 와 PKCS12 비교
JKS (Java KeyStore)
- 형식:
- Java에서 기본적으로 제공하는 키스토어 형식입니다.
- 확장자는 .jks입니다.
- 보안:
- JKS는 비밀번호로만 보호됩니다.
- 기본적으로 비밀번호는 단일 암호로 키스토어 전체를 암호화합니다.
- 지원 알고리즘:
- 주로 RSA 알고리즘을 사용한 개인 키와 인증서를 저장할 수 있습니다.
- 사용:
- 널리 사용되고 있으며, Java 기반의 애플리케이션에서 기본적으로 지원됩니다.
- 개인 키와 관련된 인증서(및 체인)를 포함하여 다양한 보안 자료를 저장할 수 있습니다.
PKCS12 (Public-Key Cryptography Standards #12)
- 형식:
- 공개 키 암호화 표준(PKCS #12)에 따라 개발된 형식입니다.
- 확장자는 .p12 또는 .pfx입니다.
- 보안:
- PKCS12는 비밀번호로 보호됩니다.
- JKS와 달리 다양한 암호화 알고리즘을 지원하며, 개인 키와 인증서(및 체인)를 포함할 수 있습니다.
- 지원 알고리즘:
- RSA, DSA, ECDSA 등 다양한 알고리즘을 지원합니다.
- 암호화된 개인 키와 인증서를 포함하여 보다 유연하게 사용할 수 있습니다.
- 사용:
- 보다 널리 사용되는 표준 형식으로, 다양한 플랫폼과 시스템에서 지원됩니다.
- 개인 키를 포함한 다양한 보안 자료를 포함할 수 있으며, 다양한 암호화 알고리즘을 지원하여 보안 요구 사항에 유연하게 대응할 수 있습니다.
요약
- 선택 기준:
- JKS: 기본적인 Java 플랫폼에서의 키스토어 사용이나 RSA 기반의 개인 키 관리에 적합합니다.
- PKCS12: 보다 넓은 플랫폼 호환성과 다양한 암호화 알고리즘 지원이 필요할 때 사용됩니다. 또한, 비밀번호 보호 및 다양한 보안 자료를 포함할 수 있는 유연성을 제공합니다.
> 우리는 어떤 암호화 방식과 어떻게 키를 관리해서 사용할까.
>> 비대칭 암호화 방식으로 PKCS12 형식의 키스토어를 통해 JWT 을 서명하고 검증합니다.
1. PKCS#12 키스토어 생성 및 JWT 생성 검증 예시
1) PKCS#12 키스토어 생성
먼저, OpenSSL을 사용하여 개인키와 인증서를 생성한 다음 이를 PKCS#12 형식으로 변환합니다.
# 개인키 생성 openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048 # 인증서 서명 요청 (CSR) 생성 openssl req -new -key private_key.pem -out request.csr # 자체 서명된 인증서 생성 openssl x509 -req -days 365 -in request.csr -signkey private_key.pem -out certificate.crt # 개인키와 인증서를 PKCS#12 파일로 변환 openssl pkcs12 -export -out keystore.p12 -inkey private_key.pem -in certificate.crt -name mykey
- 다른 서버에서 JWT 토큰의 유효성을 검증하려면, 해당 서버가 토큰을 서명할 때 사용된 공개키(Public Key)를 가지고 있어야 합니다.
2) Spring Boot 설정
> build.gradle
... implementation("org.springframework.boot:spring-boot-starter-security") //JWT implementation("io.jsonwebtoken:jjwt:0.9.1") implementation("com.sun.xml.bind:jaxb-impl") implementation("com.sun.xml.bind:jaxb-core") implementation("javax.xml.bind:jaxb-api:2.3.0") ...
3) JWT 토큰 생성 및 검증
public class JwtTokenProvider { ... // 초기에 키와 인증서를 저장할 수 있는 KeyStore 생성 및 로드한다. @PostConstruct public void init() { try { keyStore = KeyStore.getInstance("PKCS12"); FileInputStream fis = new FileInputStream("keystore.p12"); keyStore.load(fis, code.toCharArray()); fis.close(); } catch (Exception e) { throw new RuntimeException("Failed to load keystore", e); } } ... // 키스토어에서 개인키를 가져와서 토큰을 생성한다. public String generateToken(String subject) { try { PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEY_ALIAS, KEYSTORE_PASSWORD.toCharArray()); return Jwts.builder() .setSubject(subject) .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1 day .signWith(privateKey, SignatureAlgorithm.RS256) .compact(); } catch (Exception e) { throw new RuntimeException("Failed to generate token", e); } } ... // 공개키를 가져와서 토큰을 검증한다. public boolean validateToken(String token) { try { PublicKey publicKey = keyStore.getCertificate(KEY_ALIAS).getPublicKey(); Jwts.parserBuilder() .setSigningKey(publicKey) .build().parseClaimsJws(token); return true; } catch (Exception e) { return false; } } }
> 공개키 추출
PKCS#12 파일에서 공개키를 추출하려면, 먼저 openssl 명령을 사용하여 공개키를 PEM 형식으로 추출할 수 있습니다. 다음 명령어를 실행합니다:
# PKCS#12 파일에서 인증서를 추출 openssl pkcs12 -in keystore.p12 -nokeys -out certificate.pem # 인증서에서 공개키를 추출 openssl x509 -in certificate.pem -pubkey -noout -out public_key.pem
> 공개키 배포 방법
a. 키 파일 공유
공개키를 키 파일로 저장하고, 다른 서버에서 해당 파일을 읽어와서 검증에 사용하도록 설정할 수 있습니다. 예를 들어, 공개키를 public_key.pem 파일로 저장하고 다른 서버에서 이를 읽어오는 방법입니다.
b. 환경 변수 또는 구성 파일 사용
공개키를 환경 변수나 구성 파일에 저장하고, 다른 서버에서 이를 로드하여 사용합니다. 이 방법은 보안적이고 배포가 용이합니다.
c. 키 관리 서버 (KMS) 또는 비밀 관리 서비스 사용
AWS KMS, HashiCorp Vault 등의 키 관리 서비스를 사용하여 공개키를 안전하게 저장하고 배포합니다. 다른 서버는 해당 서비스에서 공개키를 가져와서 사용합니다.
반응형'웹 개발' 카테고리의 다른 글
WebClient 와 ChatClient 의 관계 (1) 2024.12.19 Pageable 을 파헤치자. (39) 2024.04.29 자바 HashTable 과 HashMap (0) 2024.03.28 User-Agent 정보 가져오기 (0) 2024.03.20 정적 코드 분석 도구 Sonarqube 도입 제안 (2) 2024.02.24