在Spring RestTemplate中禁用SSL证书验证

时间:2010-11-01 19:58:02

标签: spring validation ssl-certificate resttemplate

我在两台不同的计算机上有两个基于Spring的Web应用程序A和B.

我想从网络应用A到网络应用B进行https调用,但我在机器B中使用自签名证书。所以我的HTTPS请求失败。

如何在Spring中使用RestTemplate时禁用https证书验证?我想禁用验证,因为Web应用A和B都在内部网络中,但数据传输必须通过HTTPS进行

14 个答案:

答案 0 :(得分:36)

@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;
 }

答案 1 :(得分:28)

您需要添加的是自定义HostnameVerifier类绕过证书验证并返回true

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

这需要在您的代码中正确放置。

答案 2 :(得分:23)

基本上,您需要做的两件事是使用信任所有证书的自定义TrustStrategy ,并使用 NoopH​​ostnameVerifier()来禁用主机名验证。这是代码,包含所有相关的导入:

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;
}

答案 3 :(得分:7)

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;
           }
        }

答案 4 :(得分:5)

完整代码以禁用SSL主机名验证程序,

RestTemplate restTemplate = new RestTemplate();
//to disable ssl hostname verifier
restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory() {
   @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        if (connection instanceof HttpsURLConnection) {
            ((HttpsURLConnection) connection).setHostnameVerifier(new NoopHostnameVerifier());
        }
        super.prepareConnection(connection, httpMethod);
    }
});

答案 5 :(得分:3)

您可以将其与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 :(得分:0)

我找到了一种简单的方法

    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);

答案 7 :(得分:0)

要否决默认策略,您可以在连接restTemplate的类中创建一个简单方法:

 protected void acceptEveryCertificate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {

    TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            return true;
        }
    };

    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(
            HttpClientBuilder
                    .create()
                    .setSSLContext(SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build())
                    .build()));
}

注意:您肯定需要处理异常,因为此方法只会将异常进一步抛出!

答案 8 :(得分:0)

安全性:禁用https / TLS证书主机名检查,以下代码在spring boot rest模板中有效

*HttpsURLConnection.setDefaultHostnameVerifier(
        //SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
        // * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.NoopHostnameVerifier}
        new NoopHostnameVerifier()
);*

答案 9 :(得分:0)

此问题与SSL连接有关。当您尝试连接到某些资源时,https协议需要创建安全连接。这意味着只有您的浏览器和网站服务器知道请求主体中正在发送什么数据。这种安全性是通过存储在网站上的ssl证书来实现的,该证书由浏览器(或其他任何客户端,在我们的情况下为Apache Http Client,后面是其他任何客户端,Spring RestTemplate)与主机的首次连接下载。有RSA256加密和许多其他很棒的东西。但是到最后,如果证书未注册或无效,您将看到证书错误(HTTPS连接不安全)。要修复证书错误,网站提​​供商需要购买特定网站的证书或以某种方式修复,例如https://www.register.com/ssl-certificates

正确解决问题的方式

  • 注册SSL证书

不是解决问题的正确方法

  • download broken SSL certificate from website
  • 将SSL证书导入Java cacerts(证书存储)

    keytool -importcert -trustcacerts -noprompt -storepass changeit -alias citrix -keystore“ C:\ Program Files \ Java \ jdk-11.0.2 \ lib \ security \ cacerts”-文件citrix.cer

肮脏(不安全)方式如何解决问题

  • 使RestTemplate忽略SSL验证

    @Bean
    public RestTemplateBuilder restTemplateBuilder(@Autowired SSLContext sslContext) {
        return new RestTemplateBuilder() {
            @Override
            public ClientHttpRequestFactory buildRequestFactory() {
                return new HttpComponentsClientHttpRequestFactory(
                        HttpClients.custom().setSSLSocketFactory(
                                new SSLConnectionSocketFactory(sslContext
                                        , NoopHostnameVerifier.INSTANCE)).build());
            }
        };
    }
    
    @Bean
        public SSLContext insecureSslContext() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
           return SSLContexts.custom()
                    .loadTrustMaterial(null, (x509Certificates, s) -> true)
                    .build();
        }
    

答案 10 :(得分:0)

如果您正在使用rest模板,则可以使用这段代码

    fun getClientHttpRequestFactory(): ClientHttpRequestFactory {
        val timeout = envTimeout.toInt()
        val config = RequestConfig.custom()
            .setConnectTimeout(timeout)
            .setConnectionRequestTimeout(timeout)
            .setSocketTimeout(timeout)
            .build()

        val acceptingTrustStrategy = TrustStrategy { chain: Array<X509Certificate?>?, authType: String? -> true }

        val sslContext: SSLContext = SSLContexts.custom()
            .loadTrustMaterial(null, acceptingTrustStrategy)
            .build()

        val csf = SSLConnectionSocketFactory(sslContext)

        val client = HttpClientBuilder
            .create()
            .setDefaultRequestConfig(config)
            .setSSLSocketFactory(csf)
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build()
        return HttpComponentsClientHttpRequestFactory(client)
    }

    @Bean
    fun getRestTemplate(): RestTemplate {
        return RestTemplate(getClientHttpRequestFactory())
    }

答案 11 :(得分:0)

Java code example for HttpClient > 4.3

package com.example.teocodownloader;

import org.apache.http.conn.ssl.NoopHostnameVerifier;
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 class Example {
    public static void main(String[] args) {
        CloseableHttpClient httpClient
                = HttpClients.custom()
                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory
                = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
    }
}

顺便说一句,不要忘记将以下依赖项添加到pom文件中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

您可以找到Java code example for HttpClient < 4.3 as well

答案 12 :(得分:0)

@Bean
public RestTemplate restTemplate() throws Exception {
    SSLContext sslContext = new SSLContextBuilder()
            .loadKeyMaterial(keyStore, keyStorePassword.toCharArray(), keyStorePassword.toCharArray())
            .loadTrustMaterial(trustStore, trustStorePassword.toCharArray(), (cert, authType) -> sslTrustStrategy)
            .build();
    HostnameVerifier hostnameVerifier = sslTrustStrategy ? new NoopHostnameVerifier() :
            SSLConnectionSocketFactory.getDefaultHostnameVerifier();
    SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
    HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
    HttpComponentsClientHttpRequestFactory httpComponentsHttpClientFactory =
            new HttpComponentsClientHttpRequestFactory(httpClient);
    RestTemplate restTemplate = new RestTemplate(httpComponentsHttpClientFactory);
    return restTemplate;
}

如果 sslTrustStrategy = true,

  1. 信任由于 (cert, authType) -> sslTrustStrategy 导致的所有证书
  2. 不要只信任证书中的主机,而是信任所有主机(由于 NoopH​​ostnameVerifier,否则只信任证书中的主机)

答案 13 :(得分:0)

无需导入任何 APACHE 或任何未知包即可实现该技巧的另一种方法非常简单。

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

    private void ignoreCertificates() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

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

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

    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
     

    }

并在 RestTemplate 之前设置 ignoreCertificates():

   ignoreCertificates();
   RestTemplate restTemplate = new RestTemplate();