Java Apache Http 客户端 SSL 证书错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24720013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 14:25:51  来源:igfitidea点击:

Apache Http Client SSL certificate error

javasslhttpshttpclientapache-httpclient-4.x

提问by siki

I know it's been asked before but I tried all the solutions that I found and it's still not working.

我知道之前有人问过它,但我尝试了我找到的所有解决方案,但仍然无法正常工作。

Basically, I'm trying to get some content via Apache Http Client (4.3) and the website that I'm connecting is having some SSL issues.

基本上,我试图通过 Apache Http Client (4.3) 获取一些内容,而我连接的网站存在一些 SSL 问题。

First, I was getting and SSLExceptionwith and unrecognized_namemessage. I tried to get around this by setting the jsse.enableSNIExtensionproperty to false.

首先,我正在接收SSLExceptionunrecognized_name发送消息。我试图通过将jsse.enableSNIExtension属性设置为false.

Then, I got this exception: 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

然后,我得到了这个例外: 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

I then tried supplying my won SSLFactorythat would accept all certificates but I'm still getting the same exception. Here's my code:

然后我尝试提供SSLFactory可以接受所有证书的韩元,但我仍然遇到相同的例外情况。这是我的代码:

private static void sslTest() throws Exception {
    System.setProperty("jsse.enableSNIExtension", "false");

    SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustSelfSignedStrategy())
            .useTLS()
            .build();

    SSLConnectionSocketFactory connectionFactory =
            new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());

    CookieStore cookieStore = new BasicCookieStore();
    HttpClientContext context = HttpClientContext.create();
    context.setCookieStore(cookieStore);

    CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(connectionFactory)
            .setDefaultCookieStore(cookieStore)
            .build();

    URI uri = new URIBuilder()
            .setScheme("https")
            .setHost(BASE_URL)
            .build();

    String responseBody = httpclient.execute(new HttpGet(uri), RESPONSE_HANDLER);
}

All help is greatly appreciated!

非常感谢所有帮助!

采纳答案by ok2c

Please also note that trusting self-signed certs does not mean trusting any arbitrary cert. Try setting up your SSL context this way:

另请注意,信任自签名证书并不意味着信任任何任意证书。尝试以这种方式设置 SSL 上下文:

SSLContext sslContext = SSLContexts.custom()
        .loadTrustMaterial(null, new TrustStrategy() {

            @Override
            public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
                return true;
            }
        })
        .useTLS()
        .build();

Please also note that generally trusting certificates indiscriminately defeats the purpose of using SSL in the first place. Use when absolutely necessary or for testing only

另请注意,通常不加选择地信任证书首先违背了使用 SSL 的目的。在绝对必要或仅用于测试时使用

回答by user207421

Your truststore doesn't trust the server certificate.

您的信任库不信任服务器证书。

Allowing all hostname is an HTTPS step that can only be invoked ifthe certificate is trusted.

允许所有主机名是HTTPS一步,只能被调用,如果该证书是可信的。

回答by Elik

In Http Client 4.5.2:

在 Http 客户端 4.5.2 中:

    SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustStrategy() {

                @Override
                public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
                    return true;
                }
            })
            .build();

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslContext,
            NoopHostnameVerifier.INSTANCE);

And then:

进而:

HttpClientBuilder builder = HttpClients.custom().setSSLSocketFactory(sslsf);

回答by greensuisse

The following is for Apache 4x to trust everything

以下是 Apache 4x 信任一切

static {
    // avoid error javax.net.ssl.SSLProtocolException: handshake alert:  unrecognized_name
    System.setProperty("jsse.enableSNIExtension", "false");
}

public static HttpClientBuilder createTrustAllHttpClientBuilder() {
    try {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, (chain, authType) -> true);
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);

        return HttpClients.custom().setSSLSocketFactory(sslsf);
    }
    catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
        throw new IllegalStateException(e);
    }
}