본문 바로가기
Spring/TroubleShooting

SSLHandshakeException: PKIX ~ 인증서 관련 에러

by Mecodata 2024. 2. 15.

에러 내용

-  HTTPS 통신과 관련하여 인증서 문제가 발생했을 경우 나타남

 

에러 원인

1. 신뢰할 수 없는 CA 인증서 경우

- 새로운 CA로부터 가져온 인증서가 아직 신뢰할 수 없거나 애플리케이션이 CA가 없는 구형 버전에서 실행 중인 경우

- 해결 방법

InputStream에서 특정 CA 가져오기 CA를 사용하여 keystore 생성 → keystore를 사용하여 TrustManager 생성 TrustManager를 통해 SSLContext 초기화 인증서 확인을 위해 CA를 사용

(TrustManager에서 신뢰할 수 있는 유일한 CA)

    // Load CAs from an InputStream
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
  
    InputStream caInput = new BufferedInputStream(new FileInputStream("인증서 파일"));
    Certificate ca;
    try {
        ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
        caInput.close();
    }

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    // Tell the URLConnection to use a SocketFactory from our SSLContext
    URL url = new URL("URL 주소");
    HttpsURLConnection urlConnection =
        (HttpsURLConnection)url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);

 

2. 자체 서명한 사설 인증서인 경우 

- 개발 단계에서 CA가 아닌 사설 인증서를 사용할 경우 HttpsURLConnection을 통한 connect 과정에서 해당 에러를 마주칠 수 있음

- 해결방법

TrustManager를 생성한 뒤 이를 통해 SSLContext를 초기화 모든 인증서 연결 허용

※ 해당 방법은 보안에 취약하므로 주의할 것 (CA 인증된 공식 인증서를 사용해야 보안에 적합)

TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType){
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
} };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

 

3. 중간 CA가 존재하는데 누락된 경우

 

참고 링크 

https://developer.android.com/training/articles/security-ssl?hl=ko#java

 

HTTPS 및 SSL을 사용한 보안  |  Android 개발자  |  Android Developers

HTTPS 및 SSL을 사용한 보안 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 현재 기술적으로 전송 계층 보안(TLS)이라고 알려진 보안 소켓 레이어(SSL)는 클라이

developer.android.com

 

댓글