在Spring RestTemplate中禁用SSL证书验证

Pra*_*u R 54 validation spring ssl-certificate resttemplate

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

我想从Web应用程序A到Web应用程序B进行https调用,但是我在机器B中使用自签名证书.因此我的HTTPS请求失败.

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

Dan*_*eDM 46

@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;
 }
Run Code Online (Sandbox Code Playgroud)

  • 在您的项目中导入 Apache HttpClient (>4.4): 'org.apache.httpcomponents:httpclient:4.5.13' (3认同)

rou*_*ble 30

基本上,您需要做的两件事是使用信任所有证书自定义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;
}
Run Code Online (Sandbox Code Playgroud)

  • TrustStrategy接受TrustStrategy =(X509Certificate [] x509Certificates,String s) - > true; (4认同)
  • 谢谢你,这救了我的命。所有其他方法(使用 keytool 将导出的 .crt 添加到 java cacerts,http://blog.codeleak.pl/2016/02/skip-ssl-certificate-verification-in.html,以及大约 5~6 个其他 stackoverflow 帖子,包括答案在这个)失败了,花了我 7 个小时的时间。这个答案是我最后的希望,谢谢。 (2认同)
  • `NoopH​​ostnameVerifier` 非常重要 - 其他答案忽略了这一点。一种用例是通过环回“localhost”使用公共 SSL 证书。 (2认同)
  • 请提及支持此解决方案的 Apache HTTP 客户端库名称和版本,原始问题询问 Spring REST Template,AFAICT 不会自动引入该库,谢谢。 (2认同)
  • 这适用于 4.5.13 (https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient/4.5.13) (2认同)

Rag*_*ram 29

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

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

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

  • 这个链接对我有所帮助:http://www.jroller.com/jurberg/entry/using_a_hostnameverifier_with_spring (10认同)
  • 实际上这不在RestTemplate中.一些示例代码可从http://forum.springsource.org/showthread.php?t=60854获得.另请参阅http://stackoverflow.com/questions/1725863/ssl-handshake-issue-using-spring-resttemplate (7认同)
  • 在哪里适当的地方可以解释一下? (7认同)
  • 我正在使用 Spring 的 RestTemplate 类,你知道我如何在 RestTemplate 中做到这一点吗? (5认同)
  • 这有所帮助,谢谢。顺便说一下,您可以将其简化为lambda表达式,例如HttpsURLConnection.setDefaultHostnameVerifier((hostname,session)-> true);。 (3认同)

Sér*_*nça 19

另一种方法可以非常简单地完成该技巧,无需导入任何 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) {
     

    }
Run Code Online (Sandbox Code Playgroud)

并在 RestTemplate 之前设置ignoreCertificates():

   ignoreCertificates();
   RestTemplate restTemplate = new RestTemplate();
Run Code Online (Sandbox Code Playgroud)


Yas*_*ale 16

我找到了一个简单的方法

    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);
Run Code Online (Sandbox Code Playgroud)

使用进口

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;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
Run Code Online (Sandbox Code Playgroud)

  • 导入哪个?很难理解。 (2认同)
  • 已经两年了,什么时候增加进口 (2认同)

Ran*_*ler 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;
           }
        }
Run Code Online (Sandbox Code Playgroud)


Ami*_*har 6

您可以将其与 HTTPClient API 一起使用。

public RestTemplate getRestTemplateBypassingHostNameVerifcation() {
    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    return new RestTemplate(requestFactory);

}
Run Code Online (Sandbox Code Playgroud)

  • 此操作失败并显示“sun.security.validator.ValidatorException:PKIX 路径构建失败...”,但也被要求跳过证书检查 (3认同)

小智 6

禁用 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);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 对 (Apache) `NoopH​​ostnameVerifier` 的依赖不是必需的。只需提供 [`HostnameVerifier`](https://docs.oracle.com/javase/6/docs/api/javax/net/ssl/HostnameVerifier.html) 的(简单)自定义实现,如其他答案所示。这甚至可以是一个 lambda(https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html),例如:`(hostname, session) -&gt; true`。 (2认同)