뒤로
2026/10/23
2026년 10월 20일, 인도의 CA인 eMudhra가 운영하는 중간 인증 기관(CA) 8곳의 개인 키를 누구나 복구할 수 있다는 사실이 공개되었습니다. 브라우저는 문제가 보고된 당일에 해당 인증서를 차단했습니다. 그러나 많은 Java 애플리케이션은 지금도 이 인증서를 신뢰하고 있으며, 누군가 JDK를 업데이트하거나 트러스트스토어를 변경하기 전까지는 계속 신뢰합니다.
2026년 10월 21일, BellSoft는 많은 Java 런타임이 여전히 이 인증서를 수용한다는 테스트 결과를 발표했습니다. 이 글에서는 저희가 자체 테스트로도 확인한 그 결과를 요약하고, 브라우저는 영향을 받지 않는데 Java는 영향을 받는 이유, 시스템 점검 방법, 그리고 조치 방법을 설명합니다.
핵심 요약
- eMudhra의 중간 CA 키 8개가 침해되었습니다. 이 키를 가진 사람은 누구나 임의의 호스트 이름에 대한 인증서를 발급할 수 있으며, 해당 체인을 신뢰하는 클라이언트는 그 인증서를 수용합니다.
- 브라우저는 이를 차단하지만, Java는 자체 트러스트스토어를 사용하며 기본적으로 인증서 폐기 여부도, Certificate Transparency도 확인하지 않습니다.
- 여러 벤더의 JDK 빌드가 컨테이너 이미지를 포함해 영향받는 체인의 일부 또는 전부를 여전히 신뢰합니다.
- 벤더가 수정된 JDK를 출시할 때까지는 테스트를 거친 후 영향받는 루트 2개를 트러스트스토어에서 제거하세요. 폐기 확인을 켜는 것이 두 번째 방법입니다.
무슨 일이 있었나
eMudhra는 중간 CA 인증서 8개의 개인 키를 잘못 생성했고, 그 결과 누구나 공개 인증서로부터 키를 복구할 수 있습니다. 이는 해당 중간 인증서가 발급된 2025년 4월부터 가능했습니다.
2026년 10월 17일, 한 제보자가 8개의 키 각각으로 “We have a problem here”라는 메시지에 서명하고 그 서명을 브라우저 루트 프로그램에 보내 문제를 입증했습니다. 세부 내용은 10월 20일에 공개되었습니다.
- 중간 인증서 6개는 TLS 인증서를 발급합니다: G3B 및 G3C 세대의 eMudhra DV, OV, EV TLS CA입니다.
- 중간 인증서 2개는 코드 서명 인증서를 발급합니다.
- 각 중간 인증서는 두 가지로 존재합니다: eMudhra emSign 루트가 서명한 것과, Sectigo의
AAA Certificate Services루트가 교차 서명한 것입니다. JDK 트러스트스토어에서 체인은 두 루트 중 하나, 즉emSign ECC Root CA - G3(교차 서명 경유) 또는AAA Certificate Services에서 끝납니다.
Firefox와 Chrome은 10월 17일부터, Apple은 10월 19일부터, Microsoft는 10월 20일부터 해당 중간 인증서를 차단하고 있습니다. eMudhra는 10월 18일과 19일에 폐기 사유 CA_COMPROMISE로 8개 모두를 폐기했습니다. Linux 배포판들은 업데이트된 CA 인증서 패키지를 배포했습니다.
어떤 영향이 있나
이 키 중 하나를 가진 사람은 은행, 클라우드 제공업체, 자사 API 게이트웨이 등 어떤 호스트 이름에 대해서든 인증서를 만들 수 있습니다. 해당 체인을 신뢰하는 클라이언트는 그 인증서를 수용합니다. 침해된 네트워크나 변조된 DNS 레코드처럼 트래픽을 가로챌 수단과 결합하면, 공격자는 다음과 같은 일을 할 수 있습니다.
- Java 애플리케이션과 그 애플리케이션이 호출하는 서비스 간의 트래픽(비밀번호, API 키, 토큰 포함)을 읽고 변조합니다.
- 패키지 저장소, 업데이트 서버, 파트너 API를 사칭합니다.
- 코드 서명용 중간 인증서 2개를 통해, 신뢰할 수 있는 게시자가 만든 것처럼 보이는 코드에 서명합니다.
이 중간 인증서들은 Certificate Transparency(CT) 로그에 한 번도 기록된 적이 없으므로, CT를 강제하는 브라우저는 이를 통해 공격받을 수 없었습니다. CT를 확인하지 않는 클라이언트를 대상으로 키가 사용되었는지는 아직 알려지지 않았습니다. Java가 바로 그런 클라이언트 중 하나입니다.
Java가 여전히 이 인증서를 신뢰하는 이유
Mozilla, Google, Apple, Microsoft는 OneCRL, CRLite, CRLSets 같은 자체 채널을 통해 차단 조치를 배포했습니다. JDK의 기본 TLS 구현은 이 중 어느 것도 읽지 않습니다. 다음 세 가지 기본 설정 때문에 Java는 여전히 노출되어 있습니다.
- 자체 트러스트스토어. 애플리케이션이
javax.net.ssl.trustStore를 설정하지 않으면, Java는$JAVA_HOME/lib/security/jssecacerts파일이 있으면 그 파일의 루트를, 없으면$JAVA_HOME/lib/security/cacerts의 루트를 신뢰합니다. 벤더가 번들로 제공하는cacerts는 브라우저 차단 목록도, 운영체제의 CA 업데이트도 받지 않습니다. 관리자가 직접 편집하거나 JDK 업데이트로 교체될 때만 변경됩니다. - 폐기 확인 없음. Java는 사용자가 활성화하지 않는 한 인증서 폐기 여부를 확인하지 않으므로(
com.sun.net.ssl.checkRevocation의 기본값은 false), 기본 설정에서는 CA의 폐기 조치가 반영되지 않습니다. - Certificate Transparency 없음. JDK는 CT를 강제하지 않으므로, 브라우저 사용자를 보호한 장치가 적용되지 않습니다.
공개 페이지에는 중간 인증서와 루트의 조합마다 하나씩, 총 12개의 테스트 호스트가 나와 있습니다. BellSoft는 10월 21일 Linux에서 이를 테스트했고, 저희도 10월 23일에 같은 테스트를 반복했습니다.
| 테스트한 런타임 | 신뢰된 테스트 호스트 |
|---|---|
| Liberica JDK 21.0.10 | 12개 중 12개 |
| Liberica JDK 8u504(컨테이너 이미지) | 12개 중 12개 |
| Liberica JDK 21.0.12.1(컨테이너 이미지) | 12개 중 12개 |
| Eclipse Temurin 25.0.4.1 | 12개 중 6개(eMudhra 루트만) |
| Eclipse Temurin 21.0.12.1(컨테이너 이미지, 자체 테스트) | 12개 중 6개(eMudhra 루트만) |
| Arch Linux OpenJDK 27(시스템 CA 저장소) | 12개 중 6개(eMudhra 루트만) |
차이는 Sectigo 루트에 있습니다. Mozilla는 이미 AAA Certificate Services를 제거했고, Temurin과 Arch Linux의 트러스트스토어는 Mozilla 목록을 기반으로 만들어지므로 eMudhra 경로만 열려 있습니다. Liberica JDK 트러스트스토어에는 아직 그 루트가 포함되어 있어 두 경로가 모두 열려 있습니다.
점검해야 할 시스템
- 벤더 아카이브에서 압축을 풀었거나 벤더 설치 프로그램으로 설치한 독립형 JDK. 이들은 자체
cacerts를 사용합니다. - JDK가 포함된 컨테이너 이미지. BellSoft가 테스트한 이미지에서는 운영체제의
ca-certificates패키지를 업데이트해도 JDK의cacerts가 바뀌지 않았습니다. 더 새로운 베이스 이미지를 받아도 소용이 없었습니다. 테스트한 10월 21일자 Liberica 이미지는 여전히 12개 테스트 호스트를 모두 신뢰했습니다. javax.net.ssl.trustStore, 애플리케이션 서버 설정 또는 애플리케이션 내부에서 지정한 자체 트러스트스토어를 사용하는 애플리케이션. 두 루트가 포함되어 있는지 확인하세요.- 배포판 패키지 OpenJDK.
cacerts가 어디를 가리키는지 확인하세요. 시스템 CA 저장소에 연결되어 있다면(Arch Linux에서는/etc/ca-certificates/extracted/java-cacerts.jks에 대한 심볼릭 링크), 배포판의ca-certificates업데이트로 해결됩니다. 패치된 패키지 버전은 공개 페이지에 나와 있습니다.
JDK 점검 방법
먼저 트러스트스토어에서 두 루트를 찾습니다. 별칭(alias) 이름은 벤더마다 다르므로(Liberica JDK는 emsigneccrootcag3 [jdk], Temurin은 cn_emsign_ecc_root_ca__g3,...를 사용) 인증서 주체(subject)로 검색하세요. emSign 루트는 그 밖에도 여러 개 있지만, 영향받는 것은 emSign ECC Root CA - G3뿐입니다. JDK 9 이상에서는 다음과 같이 합니다.
keytool -list -v -cacerts -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'
Java 8의 keytool에는 -cacerts 옵션이 없으며, 트러스트스토어는 jre/ 아래에 있습니다.
keytool -list -v -keystore "$JAVA_HOME/jre/lib/security/cacerts" -storepass changeit | grep -E '^Alias name:|^Owner:' | grep -B1 -E '^Owner: CN=(emSign ECC Root CA - G3|AAA Certificate Services),'
일치하는 항목마다 별칭 이름과 그 뒤에 인증서 주체가 출력됩니다. 조치할 때 필요하므로 별칭 이름을 기록해 두세요.
다음으로 실제 연결을 테스트합니다. 이 작은 프로그램은 12개 테스트 호스트 모두에 접속하며, Java 8 및 이후의 모든 릴리스에서 실행됩니다.
import java.net.URI;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
public class Check {
public static void main(String[] args) {
for (String level : new String[]{"dv", "ov", "ev"})
for (String gen : new String[]{"g3b", "g3c"})
for (String via : new String[]{"", "-aaa"}) {
String host = level + "-" + gen + via + "-emudhra.we-have-a-problem.com";
try {
HttpsURLConnection c = (HttpsURLConnection) URI.create("https://" + host).toURL().openConnection();
c.setConnectTimeout(10000);
c.setReadTimeout(10000);
c.connect();
c.disconnect();
System.out.println("TRUSTED " + host);
} catch (SSLHandshakeException e) {
System.out.println("TLS_REJECTED " + host);
} catch (Exception e) {
System.out.println("ERROR " + host + " (" + e + ")");
}
}
}
}
JDK 11 이상에서는 java Check.java로 실행합니다. Java 8이거나 JRE만 설치된 환경에서는 먼저 javac Check.java로 컴파일한 뒤(필요하면 JDK가 있는 머신에서) java Check를 실행합니다. TRUSTED 줄은 이 JDK가 침해된 중간 인증서를 수용한다는 뜻입니다. ERROR는 호스트에 연결할 수 없었다는 뜻이며, 어느 쪽으로도 판단 근거가 되지 않습니다. 점검은 컨테이너 내부를 포함해 애플리케이션과 동일한 JDK 및 트러스트스토어 설정으로 실행하세요.
조치 방법
1. 두 루트 제거하기(수정된 JDK가 출시될 때까지 권장)
이 두 루트는 공개 페이지에서 Linux 및 macOS 사용자에게 신뢰를 해제하라고 안내하는 루트와 동일합니다. JDK를 소유한 사용자로, 점검에서 찾은 별칭 이름을 사용해 명령을 실행하세요. 예를 들어 Liberica JDK에서는 다음과 같습니다.
keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
Java 8에서는 -cacerts를 -keystore "$JAVA_HOME/jre/lib/security/cacerts"로 바꾸세요. Temurin처럼 트러스트스토어에 두 루트 중 하나만 있다면 그 하나만 삭제하세요.
JDK 설치본을 수정할 수 없다면 복사본을 편집하고 JVM이 그 복사본을 사용하도록 지정하세요.
cp "$JAVA_HOME/lib/security/cacerts" ./trimmed-cacerts
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "comodoaaaca [jdk]"
keytool -delete -keystore ./trimmed-cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
java -Djavax.net.ssl.trustStore=./trimmed-cacerts -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar
저희 테스트에서는 두 방법 모두 Liberica JDK 8과 21이 12개 테스트 호스트를 모두 거부하게 만들었고, sectigo.com, github.com 같은 일반 사이트에는 계속 정상적으로 연결되었습니다.
컨테이너 이미지는 빌드 시점에 루트를 삭제해, 새로 만드는 모든 이미지에 조치가 적용되도록 하세요.
FROM bellsoft/liberica-runtime-container:jdk-21-musl
RUN keytool -delete -cacerts -storepass changeit -alias "comodoaaaca [jdk]" \
&& keytool -delete -cacerts -storepass changeit -alias "emsigneccrootcag3 [jdk]"
Distroless 이미지와 non-root 이미지는 두 가지를 바꿔야 합니다. 셸이 없으므로 RUN의 exec 형식을 사용해 한 줄에 명령 하나씩 작성하고, 권한 없는 사용자로 실행되므로 편집할 때는 USER root로 전환했다가 이후 이미지의 원래 사용자로 되돌리세요.
팁: 루트를 제거하는 것은 중간 인증서 8개를 차단하는 것보다 영향 범위가 넓습니다. 체인이 이 루트 중 하나로만 끝나는 정상 서버는 작동하지 않게 됩니다. 적용하기 전에 애플리케이션이 호출하는 서비스를 테스트하고, JDK를 업데이트할 때마다 점검을 다시 실행하세요. 업데이트나 재설치로 원래의 cacerts가 복원될 수 있기 때문입니다.
2. 폐기 확인 켜기(선택 사항)
eMudhra가 중간 인증서 8개를 모두 폐기했으므로, 폐기 여부를 확인하는 JVM은 트러스트스토어를 변경하지 않아도 이를 거부합니다. CRL 배포 지점과 OCSP를 활성화하세요.
echo 'ocsp.enable=true' > revocation.security
java -Dcom.sun.net.ssl.checkRevocation=true \
-Dcom.sun.security.enableCRLDP=true \
-Djava.security.properties=revocation.security \
-jar app.jar
저희 테스트에서는 이 설정으로 Liberica JDK 8과 21, 그리고 Temurin 21에서 12개 테스트 호스트가 모두 거부되었습니다. 다만 이 설정은 모든 인증서의 검증 방식을 바꿉니다. JVM은 경로 검증 중에 OCSP 또는 CRL 조회를 수행하며, 폐기 상태를 확인할 수 없으면 핸드셰이크가 실패할 수 있습니다. 전역으로 활성화하기 전에 서버에서 응답 서버(responder)에 접근할 수 있는지, 지연이 얼마나 늘어나는지, 장애 시 어떻게 동작하는지 테스트하세요. 이미 폐기 확인을 켜고 운영 중이거나 루트 제거와 함께 적용할 때 사용하세요.
3. 수정된 빌드가 나오면 JDK 업데이트하기
BellSoft는 이 루트들을 제거한 Liberica JDK 업데이트를 준비 중이라고 밝혔습니다. 사용 중인 JDK 벤더의 보안 권고를 주시하세요. 업데이트가 출시되면 릴리스 노트를 읽고 eMudhra 인증서가 다뤄졌는지 확인한 뒤 설치하고, 컨테이너 이미지를 다시 빌드하고, 점검을 다시 실행하세요. 버전 번호가 높아졌다는 것만으로는 증거가 되지 않습니다.
조치 후: 노출 여부 검토하기
키는 약 18개월 동안 복구 가능한 상태였으므로, 이번 조치로 문은 닫혔지만 누군가 그 문을 이용했는지는 알 수 없습니다. 자격 증명이나 민감한 데이터를 전송하는 시스템이라면 TLS 검사, 프록시, 엔드포인트 로그에서 eMudhra 중간 인증서 8개가 발급한 인증서를 찾아보세요. 의심스러운 점이 발견되면 해당 자격 증명을 교체하세요.
장기적으로는 트러스트스토어를 의존성처럼 관리하세요. 각 트러스트스토어가 어디에 있는지, 누가 업데이트하는지, 변경 사항이 얼마나 빨리 프로덕션에 반영되는지 파악해 두어야 합니다. 이번 사건은 서버가 자체 신뢰 목록 사본을 사용할 때는 브라우저 업데이트만으로 충분하지 않다는 것을 보여 줍니다.
도움이 필요하신가요? LOGIQ는 보안 패치를 포함한 OpenJDK 및 Linux 지원을 제공합니다. 환경 내 모든 JDK와 트러스트스토어를 찾아내거나 수정 사항을 안전하게 배포하는 데 도움이 필요하시면 문의해 주세요.
참고 자료
- eMudhra Intermediate CA Compromise: 테스트 호스트와 패치된 패키지 버전이 나와 있는 공개 페이지
- BellSoft: Distrusting compromised eMudhra intermediates in Java
Global
Japan
China
Taiwan
Vietnam
Thailand
Indonesia
Portugal
Spain
France
Germany
Egypt
Russia