개발 메모장

[Java] keytool을 이용한 루트 인증서 등록(SSLHandshakeException) 본문

Java

[Java] keytool을 이용한 루트 인증서 등록(SSLHandshakeException)

yyyyMMdd 2024. 4. 18. 17:08
728x90
[org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler] 
Unexpected error occurred in scheduled task.
javax.net.ssl.SSLHandshakeException: 
sun.security.validator.ValidatorException: 
PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

 

  • API를 실행하는 서비스에서 갑자기 위와 같은 에러가 발생했습니다.

  • 방화벽 등을 체크해 봤지만 이유를 찾지 못하던 중 API 서버 측에서 SSL을 변경했다고 합니다.

  • 처리되어야 하는 데이터가 있기에 우선 원복 요청을 하였고 SSL을 변경함에 따른 조치 이행 및 에러포인트가 여러 곳일 수 있다는 가정 하에 아래와 같은 처리를 통해 해결하였습니다.

간략하게 SSL과 TLS가 무엇인지 알아보도록 하겠습니다.

 

#. SSL 이란?

  • SSL은 Security Socket Layer로 90년대 중반에 개발된 인터넷 통신 보안 프로토콜입니다.

  • SSL은 OSI 모델 중 전송계층에서 작동하며 웹 브라우징 세션 보안을 위해 네트워크를 통한 클라이언트-서버 간 통신에 사용하는  HTTP, SMTP, FTP 등의 프로토콜에 대한 암호화, 인증 등의 보안 기능을 제공합니다. HTTP + SSL을 적용한 것인 HTTPS가 대표적인 예입니다.

  • SSL은 1.0, 2.0, 3.0 등 여러 버전이 있습니다.

#. TLS 란?

  • TLS는 SSL의 보안 취약점을 해결 및 개선하기 위해 SSL 후속으로 개발되었습니다.

  • SSL과 동일한 목적으로 네트워크를 통한 클라이언트-서버 간 통신의 보안을 위한 암호화 및 데이터 무결성, 인증 등의 기능을 제공합니다.

  • TLS는 TLS1, TLS1.1, TLS1.2, TLS1.3의 버전이 있으며 1.0과 1.1은 보안 취약점으로 인해 거의 사용되지 않습니다.

  • TLS도 SSL과 동일하게 OSI 모델 중 전송계층에서 작동하며 HTTPS, SMTPS, FTPS 등의 프로토콜에 대한 통신을 보호합니다.

#. TLS 버전 문제일까?

 

  • API 통신을 위해 사용하고 있던 Java와 WAS(톰캣)의 버전이 현재로선 거의 사용하지 않는 7 버전입니다.(자바 1.7, 톰캣 7)

  • WAS로 사용하는 Tomcat > Connector > sslEnabledProtocols에서 명시적으로 설정하지 않는 경우 JVM의 기본 TLS버전을 상속하게 됩니다.

  • 자바 1.7은 일반적으로 TLS1.0을 지원하기에 기본적으로 TLS1.0을 사용합니다.

  • 서버 측에서 적용한 SSL이 버전 문제로 이슈가 있는 것이 아닌지 생각이 들어 Tomcat > server.xml에서 connector 태그에 sslEnabledProtocols을 설정했습니다.

  • 결과적으론 이 문제는 아니었습니다.
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"
	sslEnabledProtocols="TLSv1, TLSv1.1, TLSv1.2" />

 


#. 인증서 발급 기관의 변경

 

  • 서버 측에서의 SSL 적용에 대한 내용을 고지받지 못한 상태였기에 이 문제는 아닐 거라 생각했습니다.

  • 확인한 결과 기존 SSL 인증서의 발급기관과 신규 적용한 SSL 인증서의 발급기관이 달랐습니다.

  • 그렇기에 먼저 해당 기관의 인증서가 있는지 콘솔을 통해 확인합니다.
  • 사용한 명령어는 아래와 같은 역할을 합니다.
    -list : 인증서 저장소의 목록 조회
    -v : 상세 조회
    -keystore : 인증서 저장소 경로 입력
keytool -list -v -keystore "D:\자바 폴더 경로\jre\lib\security\cacerts"
  • 위 명령어를 입력하면 비밀번호를 묻는데, 비밀번호의 디폴트는 changeit이며 아래와 같이 목록이 나옵니다.

  • 이곳에 해당 인증서의 발급기관에 대한 내용이 없었습니다.

  • 따라서 API 통신 시 해당 웹에 접근가능하도록 java > cacerts에 신뢰할 수 있는 기관 인증서로 등록해줘야 합니다.

#. 인증서 다운로드 받기

 

  • 크롬 기준으로 설명드리자면 API 통신을 위한 웹에 접속하여
    주소창 왼쪽의 버튼 > 이 연결은 안전합니다. > 인증서가 유효함 > 인증서뷰어 > 세부정보 > 우측 하단 내보내기 클릭 > 저장

  • powershell 관리자 권한으로 실행
    - 자바 폴더 경로는 환경변수로 만든 {JAVA_HOME}으로 입력 가능합니다.

  • 사용한 명령어는 아래와 같은 역할을 합니다.
    -import : import 함을 명시 
    -alias : 별칭 설정
    -keystore : 인증서 저장소 경로 입력
    -storepass : 저장소 암호 입력
    -file : 인증서 파일 경로 입력
keytool.exe -import -alias 별칭 -keystore "D:\자바 폴더 경로\jre\lib\security\cacerts" -storepass changeit -file "d:\인증서 경로\인증서 파일명"
  • 아래와 같이 이 인증서를 신뢰합니까?라고 묻고 y 또는 yes를 입력하면 저장소에 추가됩니다.


  • 이렇게 처리하면 정상적으로 API가 통신하는 것을 확인할 수 있습니다.

  • 결론적으론 TLS 버전 문제는 아니었으며, 인증서의 발급기관이 클라이언트 내 신뢰할 수 있는 기관에 없었기에 오류가 발생했습니다.

  • 이러한 특이사항이 있을 경우엔 더더욱 클라이언트에게 미리 알려야 하지 않았을까 싶기도 하고 먼저 체크했다면 좀 더 수월히 진행 됐을 텐데라는 아쉬움이 남습니다.

 

===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!
===========================================================

728x90