Java 如何忽略 Apache HttpClient 4.0 中的 SSL 证书错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2703161/
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-13 11:01:37  来源:igfitidea点击:

How to ignore SSL certificate errors in Apache HttpClient 4.0

javasslapache-httpclient-4.x

提问by Viet

How do I bypass invalid SSL certificate errors with Apache HttpClient4.0?

如何使用 Apache HttpClient4.0绕过无效的 SSL 证书错误?

采纳答案by ZZ Coder

You need to create a SSLContext with your own TrustManager and create HTTPS scheme using this context. Here is the code,

您需要使用自己的 TrustManager 创建 SSLContext 并使用此上下文创建 HTTPS 方案。这是代码,

SSLContext sslContext = SSLContext.getInstance("SSL");

// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                    System.out.println("getAcceptedIssuers =============");
                    return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkServerTrusted =============");
            }
} }, new SecureRandom());

SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);

// apache HttpClient version >4.2 should use BasicClientConnectionManager
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm);

回答by eldur

In extension to ZZ Coder's answerit will be nice to override the hostnameverifier.

作为ZZ Coder 答案的扩展,覆盖主机名验证器会很好。

// ...
SSLSocketFactory sf = new SSLSocketFactory (sslContext);
sf.setHostnameVerifier(new X509HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }

    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
    }

    public void verify(String host, X509Certificate cert) throws SSLException {
    }

    public void verify(String host, SSLSocket ssl) throws IOException {
    }
});
// ...

回答by David Tinker

If all you want to do is get rid of invalid hostname errors you can just do:

如果您只想摆脱无效的主机名错误,您可以这样做:

HttpClient httpClient = new DefaultHttpClient();
SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager()
    .getSchemeRegistry().getScheme("https").getSocketFactory();
sf.setHostnameVerifier(new AllowAllHostnameVerifier());

回答by ok2c

Just for the record, there is a much simpler way to accomplish the same with HttpClient 4.1

只是为了记录,有一种更简单的方法可以使用 HttpClient 4.1 完成相同的操作

    SSLSocketFactory sslsf = new SSLSocketFactory(new TrustStrategy() {

        public boolean isTrusted(
                final X509Certificate[] chain, String authType) throws CertificateException {
            // Oh, I am easy...
            return true;
        }

    });

回答by Korny

a full working version for Apache HttpClient 4.1.3 (based on oleg's code above, but it still needed an allow_all_hostname_verifier on my system):

Apache HttpClient 4.1.3 的完整工作版本(基于上面的 oleg 代码,但它仍然需要在我的系统上使用 allow_all_hostname_verifier):

private static HttpClient trustEveryoneSslHttpClient() {
    try {
        SchemeRegistry registry = new SchemeRegistry();

        SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {

            public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
                // Oh, I am easy...
                return true;
            }

        }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        registry.register(new Scheme("https", 443, socketFactory));
        ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
        DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
        return client;
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}

Note I'm re-throwing all exceptions because really, there's not much I can do if any of this fails in a real system!

请注意,我正在重新抛出所有异常,因为实际上,如果其中任何一个在真实系统中失败,我无能为力!

回答by littletiger

        DefaultHttpClient httpclient = new DefaultHttpClient();

    SSLContext sslContext;
    try {
        sslContext = SSLContext.getInstance("SSL");

        // set up a TrustManager that trusts everything
        try {
            sslContext.init(null,
                    new TrustManager[] { new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            log.debug("getAcceptedIssuers =============");
                            return null;
                        }

                        public void checkClientTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkClientTrusted =============");
                        }

                        public void checkServerTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkServerTrusted =============");
                        }
                    } }, new SecureRandom());
        } catch (KeyManagementException e) {
        }
         SSLSocketFactory ssf = new SSLSocketFactory(sslContext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
         ClientConnectionManager ccm = this.httpclient.getConnectionManager();
         SchemeRegistry sr = ccm.getSchemeRegistry();
         sr.register(new Scheme("https", 443, ssf));            
    } catch (Exception e) {
        log.error(e.getMessage(),e);
    }

回答by Swaroop Rath

This is how I did it -

我就是这样做的——

  1. Create my own MockSSLSocketFactory (Class attached below)
  2. Use it to initialise DefaultHttpClient. Proxy settings need to be provided if a proxy is used.
  1. 创建我自己的 MockSSLSocketFactory(下面附有类)
  2. 使用它来初始化 DefaultHttpClient。如果使用代理,则需要提供代理设置。


Initialising DefaultHTTPClient -

初始化 DefaultHTTPClient -

SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory()));
    ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);

    DefaultHttpClient httpclient = new DefaultHttpClient(cm);


Mock SSL Factory -

模拟 SSL 工厂 -

public class MockSSLSocketFactory extends SSLSocketFactory {

public MockSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(trustStrategy, hostnameVerifier);
}

private static final X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
    @Override
    public void verify(String host, SSLSocket ssl) throws IOException {
        // Do nothing
    }

    @Override
    public void verify(String host, X509Certificate cert) throws SSLException {
        //Do nothing
    }

    @Override
    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
        //Do nothing
    }

    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true; 
    }
};

private static final TrustStrategy trustStrategy = new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
};
}


If behind a proxy, need to do this -

如果在代理后面,需要这样做 -

HttpParams params = new BasicHttpParams();
    params.setParameter(AuthPNames.PROXY_AUTH_PREF, getClientAuthPrefs());

DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);

httpclient.getCredentialsProvider().setCredentials(
                        new AuthScope(proxyHost, proxyPort),
                        new UsernamePasswordCredentials(proxyUser, proxyPass));

回答by Mike Slinn

If you encountered this problem when using AmazonS3Client, which embeds Apache HttpClient 4.1, you simply need to define a system property like this so that the SSL cert checker is relaxed:

如果您在使用嵌入 Apache HttpClient 4.1 的 AmazonS3Client 时遇到此问题,您只需定义一个像这样的系统属性,以便放松 SSL 证书检查器:

-Dcom.amazonaws.sdk.disableCertChecking=true

-Dcom.amazonaws.sdk.disableCertChecking=true

Mischief managed

恶作剧管理

回答by Elias Dorneles

If you are using the fluent API, you need to set it up via the Executor:

如果您使用的是fluent API,则需要通过以下方式进行设置Executor

Executor.unregisterScheme("https");
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext,
                                  SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Executor.registerScheme(new Scheme("https", 443, sslSocketFactory));

... where sslContextis the SSLContext created as shown in the ZZ Coder's answer.

...sslContext创建的 SSLContext 在哪里,如ZZ Coder的回答所示。

After that, you can do your http requests as:

之后,您可以按以下方式执行 http 请求:

String responseAsString = Request.Get("https://192.168.1.0/whatever.json")
                         .execute().getContent().asString();

Note:tested with HttpClient 4.2

注意:使用 HttpClient 4.2 测试

回答by erversteeg

All of the other answers were either deprecated or didn't work for HttpClient 4.3.

所有其他答案都已弃用或不适用于 HttpClient 4.3。

Here is a way to allow all hostnames when building an http client.

这是一种在构建 http 客户端时允许所有主机名的方法。

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setHostnameVerifier(AllowAllHostnameVerifier.INSTANCE)
    .build();

Or if you are using version 4.4 or later, the updated call looks like this:

或者,如果您使用的是 4.4 或更高版本,则更新后的调用如下所示:

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .build();