【问题标题】:Ignore self-signed certificates in Apache HTTPClient 4.5忽略 Apache HTTPClient 4.5 中的自签名证书
【发布时间】:2017-02-16 18:37:29
【问题描述】:

我正在尝试使用 Apache HTTPClient 4.5 版接受所有证书和/或接受自签名证书(教程链接here

我一直在通过 SO 上的一堆帖子解决这个问题。到目前为止,它们都没有奏效。

我不断收到此错误:Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

Apache 文档:

StackOverflow 相关问题 - 以下是我尝试过的解决方案的一些链接:

请注意,在所有这些示例中,我还传递了我之前定义的 cookie 存储和代理凭据提供程序。这些都在工作,我只是想添加 SSL 支持。

尝试#1

使用 SSLContextBuilder 创建我自己的 ssl 上下文,并使用 TrustSelfSignedStrategy 信任所有自签名策略。

SSLContextBuilder sshbuilder = new SSLContextBuilder();
sshbuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sshbuilder.build());

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

结果:没用。收到Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

尝试#2

同上,但添加PoolingHttpClientConnectionManager

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", new PlainConnectionSocketFactory())
        .register("https", sslsf)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);//max connection

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .setConnectionManager(cm)
    .build();

结果:没用。收到Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

尝试#3

只需通过覆盖TrustStrategy 来接受所有证书(不建议这样做)

SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslsf)
    .build();

结果:没用。得到Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

尝试#4

我从this answer 发现了一些有用的东西:

从 4.5 版开始,HttpClient 通过以下方式禁用 SSLv3 协议版本 默认

这是他给出的解决方案:

SSLContext sslcontext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
        sslcontext, new String[] { "TLSv1", "SSLv3" }, null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.INSTANCE)
        .register("https", sslConnectionSocketFactory)
        .build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

httpclient = HttpClients.custom()
    .setDefaultCredentialsProvider(credsProvider)
    .setDefaultCookieStore(cookieStore)
    .setSSLSocketFactory(sslConnectionSocketFactory)
    .setConnectionManager(cm)
    .build();

结果:没用。收到Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

【问题讨论】:

    标签: java ssl httpclient apache-httpclient-4.x apache-commons-httpclient


    【解决方案1】:

    我使用的是 Apache HttpClient 4.5.3,但上述解决方案都没有帮助。我总是收到错误

    PKIX 路径构建失败

    .

    我在http://www.baeldung.com/httpclient-ssl找到了解决方案

    这是我的代码:

    try {
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(null, (certificate, authType) -> true).build();
        httpClient = HttpClients.custom().setSSLContext(sslContext)
                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                .build();
    } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
        e.printStackTrace();
    }
    

    【讨论】:

      【解决方案2】:

      您通常不仅需要支持自签名证书,还需要调用多线程请求,因此需要使用池连接管理器。这是我的做法:

      private CloseableHttpClient newClient() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
          SSLContext context = SSLContexts.custom()
                  .loadTrustMaterial(TrustSelfSignedStrategy.INSTANCE)
                  .build();
      
          Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
                  .register("http", PlainConnectionSocketFactory.INSTANCE)
                  .register("https", new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE))
                  .build();
      
          PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
      
          return HttpClients.custom()
                  .setConnectionManager(connectionManager)
                  .build();
      }
      

      【讨论】:

        【解决方案3】:

        上述方法之一应该适用于自签名证书,但奇怪的是您在所有方法中都遇到了相同的异常。

        我感觉在 SSL 会话建立期间或握手协议没有被客户端或服务器接受。

        这里最好的解决方案是调试应用程序。

        如果是tomcat,在setenv.sh或setenv.bat文件中添加-Djavax.net.debug=all,然后重启服务器。

        或者你可以关注this tutorial

        连接SSL时OP只需要更改端口:

        //For HTTPS
        HttpHost httpstarget = new HttpHost("mysite.com", 443, "https");
        
        //For HTTP
        HttpHost httptarget = new HttpHost("mysite.com", 80, "http");
        

        【讨论】:

        • 是的,你是对的。我只是想去实际的网站,我认为它已经失败了,哈哈,他们可能一直在工作
        【解决方案4】:

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

        但是,当您跳过 ssl 验证时会绕过

        (s, sslSession) -> true
        

        这是安全违规,因为您不能 100% 确定您的数据是安全的,但是当使用测试数据和受信任的网站时,此解决方案可用于测试或配置

        public static HttpClient newClient() {
                    SSLContext sslcontext = null;
                    try {
                        sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
                    } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
                        e.printStackTrace();
                    }
        
                    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,
                            (s, sslSession) -> true);
        
                    return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
                            .build();
                }
        

        【讨论】:

        • 添加一些cmets和描述。
        猜你喜欢
        • 1970-01-01
        • 2013-10-31
        • 1970-01-01
        • 2018-07-26
        • 2012-08-30
        • 1970-01-01
        • 2016-07-27
        • 2021-06-01
        相关资源
        最近更新 更多