如何忽略Apache HttpClient 4.0中的SSL证书错误
如何绕过Apache HttpClient 4.0的无效SSL证书错误?
您需要使用您自己的TrustManager创buildSSLContext,并使用此上下文创buildHTTPSscheme。 这里是代码,
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.3。
这是在构buildhttp客户端时允许所有主机名的一种方法。
CloseableHttpClient httpClient = HttpClients .custom() .setHostnameVerifier(AllowAllHostnameVerifier.INSTANCE) .build();
或者,如果您使用的是版本4.4或更高版本,则更新后的调用如下所示:
CloseableHttpClient httpClient = HttpClients .custom() .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build();
只是为了logging,有一个简单的方法来完成相同的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; } });
为了logging,使用httpclient 4.3.6进行testing,并与stream利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); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>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来说,它们不起作用。 我花了几个小时尝试和耗尽可能性,但似乎有4.4的主要API变化和搬迁。
请参阅http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/上的更全面的解释;
希望有所帮助!
如果你想要做的就是摆脱无效的主机名错误,你可以这样做:
HttpClient httpClient = new DefaultHttpClient(); SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager() .getSchemeRegistry().getScheme("https").getSocketFactory(); sf.setHostnameVerifier(new AllowAllHostnameVerifier());
这是我做到的 –
- 创build我自己的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));
我们使用的HTTPClient 4.3.5,我们尝试了几乎所有的解决scheme存在于stackoverflow但没有什么,在思考和找出问题后,我们来到下面的代码,完美的作品,只是添加它之前创buildHttpClient实例。
一些方法调用时发出的请求….
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);
以正常forms继续您的请求
只需要使用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.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)) .build() )) .build();
stream利的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) { }
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); }
扩展到ZZ编码器的答案 ,将是很好的覆盖主机名称validation。
// ... 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 { } }); // ...
要接受HttpClient 4.4.x中的所有证书,创buildhttpClient时可以使用以下一行:
httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build()).build();
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); } }
注意我正在重新抛出所有exception,因为真的,如果在真正的系统中出现这种情况,我就没有办法了!
如果您使用的是stream畅的API ,则需要通过Executor
进行设置:
Executor.unregisterScheme("https"); SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Executor.registerScheme(new Scheme("https", 443, sslSocketFactory));
…其中sslContext
是创build的SSLContext,如ZZ编码器的答案中所示。
之后,你可以做你的http请求:
String responseAsString = Request.Get("https://192.168.1.0/whatever.json") .execute().getContent().asString();
注意:使用HttpClient 4.2进行testing
用4.3.3进行testing
import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class AccessProtectedResource { public static void main(String[] args) throws Exception { // Trust all certs SSLContext sslcontext = buildSSLContext(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); try { HttpGet httpget = new HttpGet("https://yoururl"); System.out.println("executing request" + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); } for (Header header : response.getAllHeaders()) { System.out.println(header); } EntityUtils.consume(entity); } finally { response.close(); } } finally { httpclient.close(); } } private static SSLContext buildSSLContext() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { SSLContext sslcontext = SSLContexts.custom() .setSecureRandom(new SecureRandom()) .loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }) .build(); return sslcontext; }
}
如果在使用embedded了Apache HttpClient 4.1的AmazonS3Client时遇到了这个问题,那么您只需要定义一个系统属性,这样就可以放松SSL证书检查器:
-Dcom.amazonaws.sdk.disableCertChecking =真
恶作剧pipe理
fwiw,使用JAX-RS 2.x的“RestEasy”实现来构build一个特殊的“信任所有”客户端的例子…
import java.io.IOException; import java.net.MalformedURLException; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import javax.ejb.Stateless; import javax.net.ssl.SSLContext; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.ssl.TrustStrategy; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.ssl.SSLContexts; @Stateless @Path("/postservice") public class PostService { private static final Logger LOG = LogManager.getLogger("PostService"); public PostService() { } @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public PostRespDTO get() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, GeneralSecurityException { //...object passed to the POST method... PostDTO requestObject = new PostDTO(); requestObject.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C"))); requestObject.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC"))); //...build special "trust all" client to call POST method... ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createTrustAllClient()); ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build(); ResteasyWebTarget target = client.target("https://localhost:7002/postRespWS").path("postrespservice"); Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestObject, MediaType.APPLICATION_JSON)); //...object returned from the POST method... PostRespDTO responseObject = response.readEntity(PostRespDTO.class); response.close(); return responseObject; } //...get special "trust all" client... private static CloseableHttpClient createTrustAllClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, TRUSTALLCERTS).useProtocol("TLS").build(); HttpClientBuilder builder = HttpClientBuilder.create(); NoopHostnameVerifier noop = new NoopHostnameVerifier(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, noop); builder.setSSLSocketFactory(sslConnectionSocketFactory); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build(); HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry); builder.setConnectionManager(ccm); return builder.build(); } private static final TrustStrategy TRUSTALLCERTS = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }; }
相关的Maven依赖关系
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <version>3.0.10.Final</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>jaxrs-api</artifactId> <version>3.0.10.Final</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> <version>3.0.10.Final</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> <type>jar</type> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency>
- org.apache.http.entity.FileEntity在Android 6(棉花糖)
- 使用HttpRequest.execute()的exception:SingleClientConnManager的使用无效:仍然分配连接
- HTTP Post请求使用HttpClient需要2秒钟,为什么?
- WebView,将本地.CSS文件添加到HTML页面?
- Android:如何获取HttpClient请求的状态码
- 我需要Android中的HttpClient的替代选项来将数据发送到PHP,因为它不再受支持
- Android HttpClient持久性cookies
- 没有MediaTypeFormatter可用于从媒体types为“text / plain”的内容读取“String”types的对象,
- 如何使用Java HttpClient库使用PHP上传文件