본문 바로가기
IT/Spring

[Spring][Error] Java PKIX path building failed:

by 강천구 2023. 6. 16.

Spring 에서 RestTemplate을 사용하여 https 통신을 하다 보면 PKIX path 오류가 발생하는 경우가 있다.

이는 JDK에서 인증서 확인 절차에서 오류가 발생한 문제다.

 

이를 해결하는 방법은 2가지가 있다.

1. 요청하고자 하는 사이트의 SSL인증서를 JDK에 추가

2. ssl 인증서 확인 절차를 무시하는 로직을 추가

 

요청하고자 하는 SSL 인증서를 다운받은 후 인증서를 추가하면 된다.

sudo  keytool -importcert -keystore ${JAVA_HOME}/lib/security/cacerts -storepass changeit -file {sslfile}

 

Https 통신에서 ssl 인증서 무시 로직은 로컬환경인 경우에만 사용하는 것을 추천한다.

예제 코드는 아래와 같다.

 

// org.apache.http

@Configuration
public class HttpClientConfig {
 
    public static RestTemplate restTemplate()
            throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
 
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
 
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
 
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
 
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        // requestFactory.setConnectionTimeout(3*1000);
        // requestFactory.setReadTimeout(3*1000);

        return new RestTemplate(requestFactory);;
    }
}

 

최신 버전의 스프링 혹은 httpclient를 사용한다면 5버전으로 변경되며 위의 로직을 그대로 사용할 수 없다.

HttpClientConnectionManager를 추가해 주어야 사용 가능하다.

 

// org.apache.hc.clinet5
// org.apache.hc.core5

@Configuration
public class HttpClientConfig {
 
    public static RestTemplate restTemplate()
            throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
 
        SSLContext sslContext = SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
 
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
 
        HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
        		.setSSLSocketFactory(csf).build()
                
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .build();
 
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        // requestFactory.setConnectionTimeout(3*1000);
        // requestFactory.setReadTimeout(3*1000);
        
        return new RestTemplate(requestFactory);
    }
}
반응형

댓글