복붙노트

[SPRING] Spring RestTemplate에서 SSL 인증서 유효성 검사 사용 안 함

SPRING

Spring RestTemplate에서 SSL 인증서 유효성 검사 사용 안 함

두 개의 다른 시스템에서 두 개의 Spring 기반 웹 응용 프로그램 A 및 B를 사용하고 있습니다.

웹 응용 프로그램 A에서 웹 응용 프로그램 B로 https 호출을 만들고 싶지만 컴퓨터 B에서 자체 서명 된 인증서를 사용하고 있습니다. 따라서 HTTPS 요청이 실패합니다.

Spring에서 RestTemplate을 사용할 때 https 인증서 유효성 검사를 비활성화하려면 어떻게합니까? 웹 앱 A와 B 모두 내부 네트워크에 있기 때문에 유효성 검사를 비활성화하고 싶지만 HTTPS를 통해 데이터 전송이 이루어져야합니다.

해결법

  1. ==============================

    1.추가해야 할 것은 사용자 정의 HostnameVerifier 클래스가 인증서 확인을 무시하고 true를 반환한다는 것입니다.

    추가해야 할 것은 사용자 정의 HostnameVerifier 클래스가 인증서 확인을 무시하고 true를 반환한다는 것입니다.

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
    

    이 코드는 코드에 적절하게 배치해야합니다.

  2. ==============================

    2.

    @Bean
    public 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);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
     }
    
  3. ==============================

    3.본질적으로해야 할 일은 모든 인증서를 신뢰하는 사용자 지정 TrustStrategy를 사용하고 NoopHostnameVerifier ()를 사용하여 호스트 이름 확인을 사용하지 않도록 설정하는 것입니다. 다음은 관련 수입을 포함한 코드입니다.

    본질적으로해야 할 일은 모든 인증서를 신뢰하는 사용자 지정 TrustStrategy를 사용하고 NoopHostnameVerifier ()를 사용하여 호스트 이름 확인을 사용하지 않도록 설정하는 것입니다. 다음은 관련 수입을 포함한 코드입니다.

    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import javax.net.ssl.SSLContext;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.client.RestTemplate;
    
    public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        };
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }
    
  4. ==============================

    4.

    Add my response with cookie :
    
        public static void main(String[] args) {
                MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
                params.add("username", testUser);
                params.add("password", testPass);
    NullHostnameVerifier verifier = new NullHostnameVerifier(); 
                MySimpleClientHttpRequestFactory requestFactory = new MySimpleClientHttpRequestFactory(verifier , rememberMeCookie);
                ResponseEntity<String> response = restTemplate.postForEntity(appUrl + "/login", params, String.class);
    
                HttpHeaders headers = response.getHeaders();
                String cookieResponse = headers.getFirst("Set-Cookie");
                String[] cookieParts = cookieResponse.split(";");
                rememberMeCookie = cookieParts[0];
                cookie.setCookie(rememberMeCookie);
    
                requestFactory = new  MySimpleClientHttpRequestFactory(verifier,cookie.getCookie());
                restTemplate.setRequestFactory(requestFactory);
        }
    
    
        public class MySimpleClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    
            private final HostnameVerifier verifier;
            private final String cookie;
    
            public MySimpleClientHttpRequestFactory(HostnameVerifier verifier ,String cookie) {
                this.verifier = verifier;
                this.cookie = cookie;
            }
    
            @Override
            protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
                if (connection instanceof HttpsURLConnection) {
                    ((HttpsURLConnection) connection).setHostnameVerifier(verifier);
                    ((HttpsURLConnection) connection).setSSLSocketFactory(trustSelfSignedSSL().getSocketFactory());
                    ((HttpsURLConnection) connection).setAllowUserInteraction(true);
                    String rememberMeCookie = cookie == null ? "" : cookie; 
                    ((HttpsURLConnection) connection).setRequestProperty("Cookie", rememberMeCookie);
                }
                super.prepareConnection(connection, httpMethod);
            }
    
            public SSLContext trustSelfSignedSSL() {
                try {
                    SSLContext ctx = SSLContext.getInstance("TLS");
                    X509TrustManager tm = new X509TrustManager() {
    
                        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                        }
    
                        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                        }
    
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                    };
                    ctx.init(null, new TrustManager[] { tm }, null);
                    SSLContext.setDefault(ctx);
                    return ctx;
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            }
    
        }
    
    
        public class NullHostnameVerifier implements HostnameVerifier {
               public boolean verify(String hostname, SSLSession session) {
                  return true;
               }
            }
    
  5. ==============================

    5.HTTPClient API와 함께 사용할 수 있습니다.

    HTTPClient API와 함께 사용할 수 있습니다.

    public RestTemplate getRestTemplateBypassingHostNameVerifcation() {
        CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        return new RestTemplate(requestFactory);
    
    }
    
  6. from https://stackoverflow.com/questions/4072585/disabling-ssl-certificate-validation-in-spring-resttemplate by cc-by-sa and MIT license