忽略Apache HTTPClient 4.5中自签名证书。

14

我正在尝试使用Apache HTTPClient 4.5版本(教程链接在这里接受所有证书或自签名证书。

我已经阅读了许多关于此问题的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();

结果: 没有起作用。 收到尝试执行请求时出错。 javax.net.ssl.SSLHandshakeException: 远程主机在握手期间关闭连接

第四次尝试

我从这个答案中找到了一些有用的东西:

从版本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();

结果:没有成功。出现了执行请求时发生错误。javax.net.ssl.SSLHandshakeException: 远程主机在握手期间关闭了连接

4个回答

18

我正在使用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();
}

7

很多时候,您不仅需要支持自签名证书,还需要调用多线程请求,并使用连接池管理器。以下是我的操作方法:

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

4

如果是自签名证书,上述方法之一应该有效,但奇怪的是在所有方法中都遇到了同样的异常。

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

最佳解决方案是调试应用程序。

对于 tomcat,可以在 setenv.sh 或 setenv.bat 文件中添加 -Djavax.net.debug=all,然后重新启动服务器。

或者您可以遵循此教程

当连接到 SSL 时,OP 只需要更改端口即可:

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

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

1
是的,你说得对。我刚试图访问实际网站,但好像它挂了,可能他们一直在处理这个问题。 - Katie

2
这个问题涉及SSL连接。当您尝试连接到某些资源时,https协议要求创建安全连接。这意味着只有您的浏览器和网站服务器知道请求正文中发送的数据。这种安全性是通过存储在网站上并在首次连接主机时由您的浏览器(或任何其他客户端,例如Apache Http Client)下载的ssl证书实现的。有RSA256加密和许多其他很酷的东西。
但是,最终结果是:如果证书未注册或无效,则会看到证书错误(HTTPS连接不安全)。为了修复证书错误,网站提供者需要为特定网站购买证书或以某种方式进行修复,例如https://www.register.com/ssl-certificates 然而,有一种方法可以绕过SSL验证,即跳过SSL验证。
(s, sslSession) -> true

这是安全违规行为,因为您不能百分之百确保数据的安全性。但是,在使用测试数据和受信任的网站时,可以将此解决方案用于测试或配置。

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

4
添加一些评论和描述。 - M--

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