如何在Spring RestTemplate中禁用SSL证书检查?

78

我正在尝试编写一项与我们的测试相关的集成测试,其中我们的测试使用Simple启动了一个嵌入式HTTPS服务器。我使用keytool创建了自签名证书,并且能够通过浏览器(具体来说是Chrome,我确实收到了关于自签名证书的警告)访问该服务器。

然而,当我尝试使用Spring RestTemplate连接时,我会遇到ResourceAccessException错误:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8088":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:557)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:444)
    at net.initech.DummySslServer.shouldConnect(DummySslServer.java:119)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1917)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
    at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:52)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:541)
    ... 33 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351)
    ... 47 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    ... 53 more

我看到了一些关于替换HostnameVerifier的建议,这些建议来自其他问题博客 文章

private static final HostnameVerifier PROMISCUOUS_VERIFIER = ( s, sslSession ) -> true;

我已经将其设置为全局和RestTemplate本身:

HttpsURLConnection.setDefaultHostnameVerifier( PROMISCUOUS_VERIFIER );

...并且在RestTemplate本身上:

final RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory( new SimpleClientHttpRequestFactory() {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        if(connection instanceof HttpsURLConnection ){
            ((HttpsURLConnection) connection).setHostnameVerifier(PROMISCUOUS_VERIFIER);
        }
        super.prepareConnection(connection, httpMethod);
    }
});

然而,我仍然遇到上述错误。我该怎么解决?
  1. 在单元测试之外本地安装证书不是一个选项,因为这样需要在每台开发机器和构建服务器上手动安装它,并会引起一系列繁琐的程序。
  2. 我们需要SSL,因为我们正在测试一个基于RestTemplate的库,并且我们正在正确配置它。

我正在使用Java 8(但也可以使用7)和Spring 4.0.3。


您需要手动配置模板使用的HTTP连接器。 - chrylis -cautiouslyoptimistic-
@chrylis,我在Java的SDK或Spring的JavaDoc中都没有看到名为HttpConnector的类。你具体指的是哪个类? - Sled
你有没有在这里检查我的答案。这对我有效。 - nilesh
请参见https://dev59.com/6nRA5IYBdhLWcg3wsgLq。 - Raedwald
Sled,你能否确认一下你是如何解决这个问题的? - PAA
13个回答

73

我希望我仍然能够找到引导我走向这个方向的源链接,但以下是最终对我起作用的代码。通过查看X509TrustManager的JavaDoc,看起来TrustManager的工作方式是在成功验证时不返回任何内容,否则会抛出异常。因此,使用null实现,它将被视为成功验证。然后您可以删除所有其他实现。

import javax.net.ssl.*;
import java.security.*;
import java.security.cert.X509Certificate;

public final class SSLUtil{

    private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers(){
                    return null;
                }
                public void checkClientTrusted( X509Certificate[] certs, String authType ){}
                public void checkServerTrusted( X509Certificate[] certs, String authType ){}
            }
        };

    public  static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
        // Install the all-trusting trust manager
        final SSLContext sc = SSLContext.getInstance("SSL");
        sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
        // Return it to the initial state (discovered by reflection, now hardcoded)
        SSLContext.getInstance("SSL").init( null, null, null );
    }

    private SSLUtil(){
        throw new UnsupportedOperationException( "Do not instantiate libraries.");
    }
}

1
@ArtB,这段代码的收集用途是什么?我在调用REST URL之前每次都需要调用SSLUtil.turnOffSslChecking()吗?请提供一些代码示例。 - Junchen Liu
这取决于您的使用情况。但我建议在单元测试的@Before方法中关闭,然后在@After中重新开启。 - Sled
在我的测试中,这确实关闭了 SSL 检查,但是 turnOn() 方法未能恢复 SSL 检查。我在下面的回答中发布了一次增量改进。 - chrisinmtown
10
我们如何使用RestTemplate来实现这一点? - PAA
1
@PAA 在初始化 RestTemplate 之前,您可以调用 SSLUtil.turnOffSslChecking()。 - sem1Colon

61

为了其他开发人员能够找到这个问题并需要适合不仅仅是单元测试的另一种解决方案:

我在博客(不是我的解决方案!归功于博客所有者)上找到了这个

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

3
这对我的情况没有用,我仍然遇到了:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure。 - MattWeiler
1
请注意,本答案假定您已经配置了Spring环境(可能是Spring-Boot),以使用Apache HTTP Client作为实现,这不是默认设置。 - chrisinmtown
在这个实现之后,我遇到了SSLPeerUnverifiedException错误。如何解决? - ojus kulkarni
1
我在使用 loadTrustMaterial 中提供的 Apache 的 new TrustSelfSignedStrategy(),但仍然出现错误。然后我按照上面的建议将其替换为 TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;,现在它可以正常工作了! - AP22
1
它对我有用。 我需要从运行SpringBoot WAR的Tomcat 8.5中调用外部Internet托管的HTTPS端点。以前,当我通过“mvn spring-boot:run”运行我的应用程序时,HTTPS端点可以成功调用,但是在Tomcat 8.5容器中运行WAR时无法调用HTTPS端点。需要添加以下依赖项: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.1</version> </dependency> - nirmalsingh

13
请看下面 @Sled 的代码改进,这个撤销方法缺少一行,现在已经通过我的测试。这个方法禁用了 RestTemplate 中的 HTTPS 证书和主机名欺骗,在使用 Spring-Boot 版本2应用程序时,使用默认的 HTTP 配置,而不是配置为使用 Apache HTTP Client。
package org.my.little.spring-boot-v2.app;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

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

/**
 * Disables and enables certificate and host-name checking in
 * HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
 * Has no effect on implementations such as Apache Http Client, Ok Http.
*/
public final class SSLUtils {

    private static final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();

    private static final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession sslSession) {
            return true;
        }
    };

    private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

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

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

    public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
        HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
        HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
        // Return it to the initial state (discovered by reflection, now hardcoded)
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, null, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    private SSLUtils() {
        throw new UnsupportedOperationException("Do not instantiate libraries.");
    }
}

1
谢谢!这个更新的解决方案对我很有用。顺便说一下,关于在 sun.net.www.protocol.https.HttpsClient 中实现主机名验证的更多信息,可以查看巨大的注释块,其中详细说明了使用的算法,可以显式设置。我最初认为只是简单地设置默认的 HostnameVerifier 就足够了,但事实并非如此,我认为这是由于使用了默认的主机名验证算法。 - mikehwang
这对我也起作用了。我在主方法中的Spring Boot应用程序启动之前调用了它。 - Chry007
1
终于!有一个解决方案实际上可以工作,而不依赖于不存在的Apache http或其他非标准配置! - Calabacin
如果对其他人不明显的话,您必须在构建RestTemplate之前(或者可能仅在使用之前)调用SSLUtils.turnOffSslChecking() - KC Baltz

10
@Bean(name = "restTemplateByPassSSL")
public RestTemplate restTemplateByPassSSL()
        throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
    HostnameVerifier hostnameVerifier = (s, sslSession) -> true;
    SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);

    return new RestTemplate(requestFactory);
}

2
欢迎来到SO。请解释一下这如何回答OP的问题。 - m02ph3u5
仔细看,这段代码片段看起来与@OhadR的答案完全相同。这有什么不同吗? - Matthew S
1
它对我有用。我需要从运行SpringBoot WAR的Tomcat 8.5调用外部托管的HTTPS端点。早期,当我通过“mvn spring-boot:run”运行我的应用程序时,HTTPS端点成功被调用,但在Tomcat 8.5容器中运行WAR时未能调用HTTPS端点。需要添加以下依赖项: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.1</version> </dependency> - nirmalsingh

7

您也可以注册您的密钥库:

private void registerKeyStore(String keyStoreName) {
    try {
        ClassLoader classLoader = this.getClass().getClassLoader();
        InputStream keyStoreInputStream = classLoader.getResourceAsStream(keyStoreName);
        if (keyStoreInputStream == null) {
            throw new FileNotFoundException("Could not find file named '" + keyStoreName + "' in the CLASSPATH");
        }

        //load the keystore
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(keyStoreInputStream, null);

        //add to known keystore 
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keystore);

        //default SSL connections are initialized with the keystore above
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustManagers, null);
        SSLContext.setDefault(sc);
    } catch (IOException | GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}

4
这里有一个解决方案可以禁用安全检查(例如,与本地主机通信)。此外,我现在看到的一些解决方案包含已弃用的方法等。
/**
 * @param configFilePath
 * @param ipAddress
 * @param userId
 * @param password
 * @throws MalformedURLException
 */
public Upgrade(String aConfigFilePath, String ipAddress, String userId, String password) {
    configFilePath = aConfigFilePath;
    baseUri = "https://" + ipAddress + ":" + PORT + "/";

    restTemplate = new RestTemplate(createSecureTransport(userId, password, ipAddress, PORT));
    restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
    restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
 }

ClientHttpRequestFactory createSecureTransport(String username,
        String password, String host, int port) {
    HostnameVerifier nullHostnameVerifier = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    credentialsProvider.setCredentials(
            new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), credentials);

    HttpClient client = HttpClientBuilder.create()
            .setSSLHostnameVerifier(nullHostnameVerifier)
            .setSSLContext(createContext())
            .setDefaultCredentialsProvider(credentialsProvider).build();

    HttpComponentsClientHttpRequestFactory requestFactory = 
            new HttpComponentsClientHttpRequestFactory(client);

    return requestFactory;
}

private SSLContext createContext() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        SSLContext.setDefault(sc);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        return sc;

    } catch (Exception e) {
    }
    return null;
}

4

虽然有些晚了,但这里提供我的解决方案。使用这个类,您可以在项目中关闭所有SSL验证。

import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;


@Slf4j
@Component
public class SslWarningRemover {

    public SslWarningRemover() {
        log.info("Disabling SSL warning...");
        try {
            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 sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            
            log.info("SSL verification disabled");
        } catch (Exception e) {
            log.error("Error while trying to disable SSL verification: " + e.getMessage(), e);
        }
        
        log.info("SSL warning process remover has finished!");
    }
}

如果你想在单个RestTemplate中禁用SSL验证,请尝试以下操作:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
    
    private static final HostnameVerifier PROMISCUOUS_VERIFIER = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    
    private static final TrustManager[] ALL_CERT_TRUST_MANAGER = new TrustManager[] {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    
                }
                
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    
                }
            }
    };
    
    private static SSLContext ALL_CERT_TRUST_SSLCONTEXT = null;
    
    static {
        try {
            ALL_CERT_TRUST_SSLCONTEXT = SSLContext.getInstance("SSL");
            ALL_CERT_TRUST_SSLCONTEXT.init(null, ALL_CERT_TRUST_MANAGER, new SecureRandom());
        } catch (Exception e) {
            log.error("Error disabling SSL verification");
            log.error(e.getMessage(), e);
        }
    }
    
    
    private boolean disableSslVerification = false;
    
    public CustomClientHttpRequestFactory(int connectTimeout, int readTimeout, boolean disableSslVerification) {
        this.setConnectTimeout(connectTimeout);
        this.setReadTimeout(readTimeout);
        this.disableSslVerification = disableSslVerification;
    }
    
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        if (disableSslVerification && ALL_CERT_TRUST_SSLCONTEXT != null && connection instanceof HttpsURLConnection) {
            ((HttpsURLConnection) connection).setHostnameVerifier(PROMISCUOUS_VERIFIER);
            ((HttpsURLConnection) connection).setSSLSocketFactory(ALL_CERT_TRUST_SSLCONTEXT.getSocketFactory());
        }
        super.prepareConnection(connection, httpMethod);
    }
    
}

接着,当你创建 RestTemplate 对象实例时,请使用以下代码:

RestTemplate restTemplate = new RestTemplate(new CustomClientHttpRequestFactory(connectTimeout, readTimeout, disableSslVerification));

使用 disableSslVerification 参数,并将其设置为 true

这在我的环境下与Spring Boot 1.5一起工作。 - MXPLUX

2

我知道这个回答太旧了,但我找不到像这样的解决方案。

以下是使用Jersey客户端为我工作的代码:

Original Answer翻译成"最初的回答"

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;

import javax.net.ssl.*;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

public class Testi {

static {
    disableSslVerification();
}
private static void disableSslVerification() {
    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}

public Testi() {
    MultivaluedHashMap<String, Object> headers = new MultivaluedHashMap<>();
    //... initialize headers

    Form form = new Form();
    Entity<Form> entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE);
    // initialize entity ...

    WebTarget target = getWebTarget();
    Object responseResult = target.path("api/test/path...").request()
            .headers(headers).post(entity, Object.class);

}

public static void main(String args[]) {
    new Testi();
}

private WebTarget getWebTarget() {
    ClientConfig clientConfig = new ClientConfig();
    clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 30000);
    clientConfig.property(ClientProperties.READ_TIMEOUT, 30000);

    SSLContext sc = getSSLContext();
    Client client = ClientBuilder.newBuilder().sslContext(sc).withConfig(clientConfig).build();
    WebTarget target = client.target("...url...");
    return target;
}

private SSLContext getSSLContext() {
    try {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }
        };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        return sc;
    } catch (NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
    }
    return null;
}
}

0

我想分享一下,至少对我自己来说,基于其他答案的代码。

// Spring Boot 2.7.5 / Java 11
@PostConstruct
private void onPostConstruct() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
    // http://www.chrispad.com/2019/02/disable-certificate-verification-using.html
    var sslContext = SSLContexts.custom().loadTrustMaterial((c, at) -> true).build();
    var socketFactory = new SSLConnectionSocketFactory(sslContext, (h, s) -> true);
    var httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
    var requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);
    template = templateBuilder.requestFactory(() -> requestFactory).build();
}

private final RestTemplateBuilder templateBuilder;

private RestTemplate template;:

0
            private static void disableSslVerification() {
            try
            {
                // Create a trust manager that does not validate certificate chains
                TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
                };

                // Install the all-trusting trust manager
                SSLContext sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

                // Create all-trusting host name verifier
                HostnameVerifier allHostsValid = new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                };

                // Install the all-trusting host verifier
                HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接