如何使用Apache HttpClient 4.0 绕过无效的SSL证书错误?
所有其他答案都已弃用或不适用于HttpClient 4.3.
这是一种在构建http客户端时允许所有主机名的方法.
CloseableHttpClient httpClient = HttpClients .custom() .setHostnameVerifier(AllowAllHostnameVerifier.INSTANCE) .build();
或者,如果您使用的是4.4或更高版本,则更新的调用如下所示:
CloseableHttpClient httpClient = HttpClients .custom() .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build();
您需要使用自己的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);
只是为了记录,有一个更简单的方法来实现与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; } });
只需要使用较新的HttpClient 4.5来做这件事,看起来他们已经弃用了4.4之后的一些东西,所以这里的代码片段适用于我并使用最新的API:
final SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, (x509CertChain, authType) -> true) .build(); return HttpClientBuilder.create() .setSSLContext(sslContext) .setConnectionManager( new PoolingHttpClientConnectionManager( RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)) .build() )) .build();
为了记录,使用httpclient 4.3.6测试并与流畅的api的Executor兼容:
CloseableHttpClient httpClient = HttpClients.custom(). setHostnameVerifier(new AllowAllHostnameVerifier()). setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build()).build();
对于Apache HttpClient 4.4:
HttpClientBuilder b = HttpClientBuilder.create(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { return true; } }).build(); b.setSslcontext( sslContext); // or SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); RegistrysocketFactoryRegistry = RegistryBuilder. create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) .build(); // allows multi-threaded use PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry); b.setConnectionManager( connMgr); HttpClient client = b.build();
这是从我们的实际工作实施中提取的.
其他答案很受欢迎,但对于HttpClient 4.4,它们不起作用.我花了几个小时尝试和耗尽可能性,但似乎已经有非常重要的API更改和重新定位4.4.
另请参阅以下网址上的更全面的解释:http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/
希望有所帮助!
Apache HttpClient 4.5.5
HttpClient httpClient = HttpClients .custom() .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build()) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build();
没有使用过弃用的API.
简单可验证的测试用例:
package org.apache.http.client.test; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; public class ApacheHttpClientTest { private HttpClient httpClient; @Before public void initClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { httpClient = HttpClients .custom() .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build()) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build(); } @Test public void apacheHttpClient455Test() throws IOException { executeRequestAndVerifyStatusIsOk("https://expired.badssl.com"); executeRequestAndVerifyStatusIsOk("https://wrong.host.badssl.com"); executeRequestAndVerifyStatusIsOk("https://self-signed.badssl.com"); executeRequestAndVerifyStatusIsOk("https://untrusted-root.badssl.com"); executeRequestAndVerifyStatusIsOk("https://revoked.badssl.com"); executeRequestAndVerifyStatusIsOk("https://pinning-test.badssl.com"); executeRequestAndVerifyStatusIsOk("https://sha1-intermediate.badssl.com"); } private void executeRequestAndVerifyStatusIsOk(String url) throws IOException { HttpUriRequest request = new HttpGet(url); HttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); assert statusCode == 200; } }
如果您只想摆脱无效的主机名错误,您可以这样做:
HttpClient httpClient = new DefaultHttpClient(); SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager() .getSchemeRegistry().getScheme("https").getSocketFactory(); sf.setHostnameVerifier(new AllowAllHostnameVerifier());
我们正在使用HTTPClient 4.3.5,我们尝试了几乎所有解决方案都存在于stackoverflow上但没有任何问题,在思考并找出问题之后,我们来看下面的代码,它完美地工作,只需在创建HttpClient实例之前添加它.
在发布请求时调用的一些方法....
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); HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSF).build(); HttpPost postRequest = new HttpPost(url);
以正常形式继续您的请求
使用流畅的4.5.2我必须进行以下修改才能使其正常工作.
try { 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) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build(); String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something") .connectTimeout(1000) .socketTimeout(1000)).returnContent().asString(); } catch (Exception e) { }
这就是我做到的 -
创建我自己的MockSSLSocketFactory(下面附带的类)
用它来初始化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);
模拟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; } }; }
如果在代理后面,需要这样做 -
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));