How to ignore SSL certificate (trust all) for Apache HttpClient 4.3?
如何忽略Apache HttpClient 4.3的SSL证书(全部信任)?
All the answers that I have found on SO treat previous versions, and the API changed.
我在SO上找到的所有答案都会处理以前的版本,并且API已更改。
Related:
有关:
- How to ignore SSL certificate errors in Apache HttpClient 4.0
- 如何忽略Apache HttpClient 4.0中的SSL证书错误
- How to handle invalid SSL certificates with Apache HttpClient?
- 如何使用Apache HttpClient处理无效的SSL证书?
- Need to trust all the certificates during the development using Spring
- 使用Spring开发期间需要信任所有证书
- Ignore SSL Certificate Errors with Java
- 使用Java忽略SSL证书错误
Edit:
编辑:
- It is only for test purposes. Kids, don't try it at home (or in production)
- 它仅用于测试目的。孩子们,不要在家里(或在生产中)尝试
14 个解决方案
#1
122
The code below works for trusting self-signed certificates. You have to use the TrustSelfSignedStrategy when creating your client:
以下代码适用于信任自签名证书。创建客户端时必须使用TrustSelfSignedStrategy:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet("https://some-server");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
response.close();
}
I did not include the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
on purpose: The point was to allow testing with self signed certificates so you don't have to acquire a proper certificate from a certification authority. You can easily create a self-signed certificate with the correct host name, so do that instead of adding the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
flag.
我没有故意包含SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER:重点是允许使用自签名证书进行测试,这样您就不必从证书颁发机构获取适当的证书。您可以使用正确的主机名轻松创建自签名证书,这样做而不是添加SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER标志。
#2
74
If you are using PoolingHttpClientConnectionManager procedure above doesn't work, custom SSLContext is ignored. You have to pass socketFactoryRegistry in contructor when creating PoolingHttpClientConnectionManager.
如果您使用上面的PoolingHttpClientConnectionManager过程不起作用,则忽略自定义SSLContext。创建PoolingHttpClientConnectionManager时,必须在构造函数中传递socketFactoryRegistry。
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext, new X509HostnameVerifier() {
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create().register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm).build();
#3
24
As an addition to the answer of @mavroprovato, if you want to trust all certificates instead of just self-signed, you'd do (in the style of your code)
作为@mavroprovato答案的补充,如果你想信任所有证书而不仅仅是自签名,你可以(以你的代码的方式)
builder.loadTrustMaterial(null, new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
or (direct copy-paste from my own code):
或(从我自己的代码直接复制粘贴):
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.ssl.SSLContexts;
// ...
SSLContext sslContext = SSLContexts
.custom()
//FIXME to contain real trust store
.loadTrustMaterial(new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
return true;
}
})
.build();
And if you want to skip hostname verification as well, you need to set
如果你想跳过主机名验证,你需要设置
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE).build();
as well. (ALLOW_ALL_HOSTNAME_VERIFIER is deprecated).
同样。 (不推荐使用ALLOW_ALL_HOSTNAME_VERIFIER)。
Obligatory warning: you shouldn't really do this, accepting all certificates is a bad thing. However there are some rare use cases where you want to do this.
强制警告:你不应该这样做,接受所有证书是件坏事。但是,有一些罕见的用例你想要这样做。
As a note to code previously given, you'll want to close response even if httpclient.execute() throws an exception
作为前面给出的代码的注释,即使httpclient.execute()抛出异常,您也希望关闭响应
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpGet);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
if (response != null) {
response.close();
}
}
Code above was tested using
上面的代码使用测试
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
And for the interested, here's my full test set:
感兴趣的是,这是我的完整测试集:
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.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class TrustAllCertificatesTest {
final String expiredCertSite = "https://expired.badssl.com/";
final String selfSignedCertSite = "https://self-signed.badssl.com/";
final String wrongHostCertSite = "https://wrong.host.badssl.com/";
static final TrustStrategy trustSelfSignedStrategy = new TrustSelfSignedStrategy();
static final TrustStrategy trustAllStrategy = new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
};
@Test
public void testSelfSignedOnSelfSignedUsingCode() throws Exception {
doGet(selfSignedCertSite, trustSelfSignedStrategy);
}
@Test(expected = SSLHandshakeException.class)
public void testExpiredOnSelfSignedUsingCode() throws Exception {
doGet(expiredCertSite, trustSelfSignedStrategy);
}
@Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnSelfSignedUsingCode() throws Exception {
doGet(wrongHostCertSite, trustSelfSignedStrategy);
}
@Test
public void testSelfSignedOnTrustAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy);
}
@Test
public void testExpiredOnTrustAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy);
}
@Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnTrustAllUsingCode() throws Exception {
doGet(wrongHostCertSite, trustAllStrategy);
}
@Test
public void testSelfSignedOnAllowAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
@Test
public void testExpiredOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
@Test
public void testWrongHostOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
public void doGet(String url, TrustStrategy trustStrategy, HostnameVerifier hostnameVerifier) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier(hostnameVerifier).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
public void doGet(String url, TrustStrategy trustStrategy) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
}
(working test project in github)
(github中的工作测试项目)
#4
18
One small addition to the answer by vasekt:
vasekt对答案的一个小补充:
The provided solution with the SocketFactoryRegistry works when using PoolingHttpClientConnectionManager.
使用PoolingHttpClientConnectionManager时,提供的SocketFactoryRegistry解决方案可以正常工作。
However, connections via plain http don't work any longer then. You have to add a PlainConnectionSocketFactory for the http protocol additionally to make them work again:
但是,通过普通http的连接不再起作用。您还必须为http协议添加一个PlainConnectionSocketFactory,以使它们再次工作:
Registry<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslsf)
.register("http", new PlainConnectionSocketFactory()).build();
#5
13
After trying various options, following configuration worked for both http and https
尝试各种选项后,以下配置适用于http和https
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
//System.setProperty("jsse.enableSNIExtension", "false"); //""
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.setConnectionManager(cm)
.build();
I am using http-client 4.3.3 -
我使用的是http-client 4.3.3 -
compile 'org.apache.httpcomponents:httpclient:4.3.3'
编译'org.apache.httpcomponents:httpclient:4.3.3'
#6
6
Simpler and shorter working code:
更简单,更短的工作代码:
We are using HTTPClient 4.3.5 and we tried almost all solutions exist on the * but nothing, After thinking and figuring out the problem, we come to the following code which works perfectly, just add it before creating HttpClient instance.
我们正在使用HTTPClient 4.3.5,我们尝试了几乎所有解决方案都存在于*上但没有任何问题,在思考并找出问题之后,我们来看下面的代码,它完美地工作,只需在创建HttpClient实例之前添加它。
some method which you use to make post request...
你用来发帖请求的一些方法......
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);
continue calling and using HttpPost instance in the normal form
继续以正常形式调用和使用HttpPost实例
#7
5
When using http client 4.5 I had to use the javasx.net.ssl.HostnameVerifier to allow any hostname (for testing purposes). Here is what I ended up doing:
使用http客户端4.5时,我必须使用javasx.net.ssl.HostnameVerifier来允许任何主机名(用于测试目的)。这是我最终做的事情:
CloseableHttpClient httpClient = null;
try {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
HostnameVerifier hostnameVerifierAllowAll = new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), hostnameVerifierAllowAll);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("192.168.30.34", 8443),
new UsernamePasswordCredentials("root", "password"));
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.setDefaultCredentialsProvider(credsProvider)
.build();
HttpGet httpGet = new HttpGet("https://192.168.30.34:8443/axis/services/getStuff?firstResult=0&maxResults=1000");
CloseableHttpResponse response = httpClient.execute(httpGet);
int httpStatus = response.getStatusLine().getStatusCode();
if (httpStatus >= 200 && httpStatus < 300) { [...]
} else {
throw new ClientProtocolException("Unexpected response status: " + httpStatus);
}
} catch (Exception ex) {
ex.printStackTrace();
}
finally {
try {
httpClient.close();
} catch (IOException ex) {
logger.error("Error while closing the HTTP client: ", ex);
}
}
#8
5
Here's a working distillation of the above techniques, equivalent to "curl --insecure":
这是上述技术的工作升级,相当于“curl --insecure”:
HttpClient getInsecureHttpClient() throws GeneralSecurityException {
TrustStrategy trustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
};
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
return HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(),
hostnameVerifier))
.build();
}
#9
3
On top of PoolingHttpClientConnectionManager
along with Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build();
If you want an asynchronous httpclient using PoolingNHttpClientConnectionManager
the code shoudl be similar to following
在PoolingHttpClientConnectionManager和Registry
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SchemeIOSessionStrategy sslioSessionStrategy = new SSLIOSessionStrategy(sslContext,
new HostnameVerifier(){
@Override
public boolean verify(String hostname, SSLSession session) {
return true;// TODO as of now allow all hostnames
}
});
Registry<SchemeIOSessionStrategy> sslioSessionRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create().register("https", sslioSessionStrategy).build();
PoolingNHttpClientConnectionManager ncm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry);
CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build();
asyncHttpClient.start();
#10
2
class ApacheHttpClient {
/***
* This is a https get request that bypasses certificate checking and hostname verifier.
* It uses basis authentication method.
* It is tested with Apache httpclient-4.4.
* It dumps the contents of a https page on the console output.
* It is very similar to http get request, but with the additional customization of
* - credential provider, and
* - SSLConnectionSocketFactory to bypass certification checking and hostname verifier.
* @param path String
* @param username String
* @param password String
* @throws IOException
*/
public void get(String path, String username, String password) throws IOException {
final CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(createCredsProvider(username, password))
.setSSLSocketFactory(createGenerousSSLSocketFactory())
.build();
final CloseableHttpResponse response = httpClient.execute(new HttpGet(path));
try {
HttpEntity entity = response.getEntity();
if (entity == null)
return;
System.out.println(EntityUtils.toString(entity));
} finally {
response.close();
httpClient.close();
}
}
private CredentialsProvider createCredsProvider(String username, String password) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
return credsProvider;
}
/***
*
* @return SSLConnectionSocketFactory that bypass certificate check and bypass HostnameVerifier
*/
private SSLConnectionSocketFactory createGenerousSSLSocketFactory() {
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{createGenerousTrustManager()}, new SecureRandom());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
}
private X509TrustManager createGenerousTrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
}
}
#11
1
(I would have added a comment directly to vasekt's answer but I don't have enough reputation points (not sure the logic there)
(我会直接在vasekt的答案中添加评论,但我没有足够的声望点(不确定那里的逻辑)
Anyway... what I wanted to say is that even if you aren't explicitly creating/asking for a PoolingConnection, doesn't mean you aren't getting one.
无论如何...我想说的是,即使你没有明确地创建/要求PoolingConnection,也不意味着你没有得到它。
I was going crazy trying to figure out why the original solution didn't work for me, but I ignored vasekt's answer as it "didn't apply to my case" - wrong!
我疯狂地想弄清楚为什么原来的解决方案不适合我,但是我忽略了vasekt的答案,因为它“不适用于我的情况” - 错了!
I was staring at my stack-trace when low and behold I saw a PoolingConnection in the middle of it. Bang - I tired his addition and success!! (our demo is tomorrow and I was getting desperate) :-)
我低时盯着我的堆栈跟踪,看到我在它的中间看到了一个PoolingConnection。砰 - 我厌倦了他的加成和成功!! (我们的演示是明天,我变得绝望):-)
#12
1
Trust All Certs in Apache HTTP Client
信任Apache HTTP客户端中的所有证书
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sc);
httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
#13
0
You can use following code snippet for get the HttpClient instance without ssl certification checking.
您可以使用以下代码片段来获取没有ssl认证检查的HttpClient实例。
private HttpClient getSSLHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
LogLoader.serverLog.trace("In getSSLHttpClient()");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
context.init(null, new TrustManager[] { tm }, null);
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(context);
builder.setSSLSocketFactory(sslConnectionFactory);
PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionFactory).register("http", plainConnectionSocketFactory).build();
PoolingHttpClientConnectionManager ccm = new PoolingHttpClientConnectionManager(registry);
ccm.setMaxTotal(BaseConstant.CONNECTION_POOL_SIZE);
ccm.setDefaultMaxPerRoute(BaseConstant.CONNECTION_POOL_SIZE);
builder.setConnectionManager((HttpClientConnectionManager) ccm);
builder.disableRedirectHandling();
LogLoader.serverLog.trace("Out getSSLHttpClient()");
return builder.build();
}
#14
0
If you are using HttpClient 4.5.x
, your code can be similar to the following:
如果您使用的是HttpClient 4.5.x,您的代码可能类似于以下内容:
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,
TrustSelfSignedStrategy.INSTANCE).build();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE);
HttpClient httpClient = HttpClients.custom()
.setDefaultCookieStore(new BasicCookieStore())
.setSSLSocketFactory(sslSocketFactory)
.build();
#1
122
The code below works for trusting self-signed certificates. You have to use the TrustSelfSignedStrategy when creating your client:
以下代码适用于信任自签名证书。创建客户端时必须使用TrustSelfSignedStrategy:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet("https://some-server");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
response.close();
}
I did not include the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
on purpose: The point was to allow testing with self signed certificates so you don't have to acquire a proper certificate from a certification authority. You can easily create a self-signed certificate with the correct host name, so do that instead of adding the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
flag.
我没有故意包含SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER:重点是允许使用自签名证书进行测试,这样您就不必从证书颁发机构获取适当的证书。您可以使用正确的主机名轻松创建自签名证书,这样做而不是添加SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER标志。
#2
74
If you are using PoolingHttpClientConnectionManager procedure above doesn't work, custom SSLContext is ignored. You have to pass socketFactoryRegistry in contructor when creating PoolingHttpClientConnectionManager.
如果您使用上面的PoolingHttpClientConnectionManager过程不起作用,则忽略自定义SSLContext。创建PoolingHttpClientConnectionManager时,必须在构造函数中传递socketFactoryRegistry。
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext, new X509HostnameVerifier() {
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create().register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm).build();
#3
24
As an addition to the answer of @mavroprovato, if you want to trust all certificates instead of just self-signed, you'd do (in the style of your code)
作为@mavroprovato答案的补充,如果你想信任所有证书而不仅仅是自签名,你可以(以你的代码的方式)
builder.loadTrustMaterial(null, new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
or (direct copy-paste from my own code):
或(从我自己的代码直接复制粘贴):
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.ssl.SSLContexts;
// ...
SSLContext sslContext = SSLContexts
.custom()
//FIXME to contain real trust store
.loadTrustMaterial(new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
return true;
}
})
.build();
And if you want to skip hostname verification as well, you need to set
如果你想跳过主机名验证,你需要设置
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE).build();
as well. (ALLOW_ALL_HOSTNAME_VERIFIER is deprecated).
同样。 (不推荐使用ALLOW_ALL_HOSTNAME_VERIFIER)。
Obligatory warning: you shouldn't really do this, accepting all certificates is a bad thing. However there are some rare use cases where you want to do this.
强制警告:你不应该这样做,接受所有证书是件坏事。但是,有一些罕见的用例你想要这样做。
As a note to code previously given, you'll want to close response even if httpclient.execute() throws an exception
作为前面给出的代码的注释,即使httpclient.execute()抛出异常,您也希望关闭响应
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpGet);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
if (response != null) {
response.close();
}
}
Code above was tested using
上面的代码使用测试
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
And for the interested, here's my full test set:
感兴趣的是,这是我的完整测试集:
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.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class TrustAllCertificatesTest {
final String expiredCertSite = "https://expired.badssl.com/";
final String selfSignedCertSite = "https://self-signed.badssl.com/";
final String wrongHostCertSite = "https://wrong.host.badssl.com/";
static final TrustStrategy trustSelfSignedStrategy = new TrustSelfSignedStrategy();
static final TrustStrategy trustAllStrategy = new TrustStrategy(){
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
};
@Test
public void testSelfSignedOnSelfSignedUsingCode() throws Exception {
doGet(selfSignedCertSite, trustSelfSignedStrategy);
}
@Test(expected = SSLHandshakeException.class)
public void testExpiredOnSelfSignedUsingCode() throws Exception {
doGet(expiredCertSite, trustSelfSignedStrategy);
}
@Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnSelfSignedUsingCode() throws Exception {
doGet(wrongHostCertSite, trustSelfSignedStrategy);
}
@Test
public void testSelfSignedOnTrustAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy);
}
@Test
public void testExpiredOnTrustAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy);
}
@Test(expected = SSLPeerUnverifiedException.class)
public void testWrongHostOnTrustAllUsingCode() throws Exception {
doGet(wrongHostCertSite, trustAllStrategy);
}
@Test
public void testSelfSignedOnAllowAllUsingCode() throws Exception {
doGet(selfSignedCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
@Test
public void testExpiredOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
@Test
public void testWrongHostOnAllowAllUsingCode() throws Exception {
doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE);
}
public void doGet(String url, TrustStrategy trustStrategy, HostnameVerifier hostnameVerifier) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).setSSLHostnameVerifier(hostnameVerifier).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
public void doGet(String url, TrustStrategy trustStrategy) throws Exception {
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(trustStrategy);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
}
}
(working test project in github)
(github中的工作测试项目)
#4
18
One small addition to the answer by vasekt:
vasekt对答案的一个小补充:
The provided solution with the SocketFactoryRegistry works when using PoolingHttpClientConnectionManager.
使用PoolingHttpClientConnectionManager时,提供的SocketFactoryRegistry解决方案可以正常工作。
However, connections via plain http don't work any longer then. You have to add a PlainConnectionSocketFactory for the http protocol additionally to make them work again:
但是,通过普通http的连接不再起作用。您还必须为http协议添加一个PlainConnectionSocketFactory,以使它们再次工作:
Registry<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslsf)
.register("http", new PlainConnectionSocketFactory()).build();
#5
13
After trying various options, following configuration worked for both http and https
尝试各种选项后,以下配置适用于http和https
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
//System.setProperty("jsse.enableSNIExtension", "false"); //""
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.setConnectionManager(cm)
.build();
I am using http-client 4.3.3 -
我使用的是http-client 4.3.3 -
compile 'org.apache.httpcomponents:httpclient:4.3.3'
编译'org.apache.httpcomponents:httpclient:4.3.3'
#6
6
Simpler and shorter working code:
更简单,更短的工作代码:
We are using HTTPClient 4.3.5 and we tried almost all solutions exist on the * but nothing, After thinking and figuring out the problem, we come to the following code which works perfectly, just add it before creating HttpClient instance.
我们正在使用HTTPClient 4.3.5,我们尝试了几乎所有解决方案都存在于*上但没有任何问题,在思考并找出问题之后,我们来看下面的代码,它完美地工作,只需在创建HttpClient实例之前添加它。
some method which you use to make post request...
你用来发帖请求的一些方法......
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);
continue calling and using HttpPost instance in the normal form
继续以正常形式调用和使用HttpPost实例
#7
5
When using http client 4.5 I had to use the javasx.net.ssl.HostnameVerifier to allow any hostname (for testing purposes). Here is what I ended up doing:
使用http客户端4.5时,我必须使用javasx.net.ssl.HostnameVerifier来允许任何主机名(用于测试目的)。这是我最终做的事情:
CloseableHttpClient httpClient = null;
try {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
HostnameVerifier hostnameVerifierAllowAll = new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), hostnameVerifierAllowAll);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("192.168.30.34", 8443),
new UsernamePasswordCredentials("root", "password"));
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.setDefaultCredentialsProvider(credsProvider)
.build();
HttpGet httpGet = new HttpGet("https://192.168.30.34:8443/axis/services/getStuff?firstResult=0&maxResults=1000");
CloseableHttpResponse response = httpClient.execute(httpGet);
int httpStatus = response.getStatusLine().getStatusCode();
if (httpStatus >= 200 && httpStatus < 300) { [...]
} else {
throw new ClientProtocolException("Unexpected response status: " + httpStatus);
}
} catch (Exception ex) {
ex.printStackTrace();
}
finally {
try {
httpClient.close();
} catch (IOException ex) {
logger.error("Error while closing the HTTP client: ", ex);
}
}
#8
5
Here's a working distillation of the above techniques, equivalent to "curl --insecure":
这是上述技术的工作升级,相当于“curl --insecure”:
HttpClient getInsecureHttpClient() throws GeneralSecurityException {
TrustStrategy trustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) {
return true;
}
};
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
return HttpClients.custom()
.setSSLSocketFactory(new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(),
hostnameVerifier))
.build();
}
#9
3
On top of PoolingHttpClientConnectionManager
along with Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build();
If you want an asynchronous httpclient using PoolingNHttpClientConnectionManager
the code shoudl be similar to following
在PoolingHttpClientConnectionManager和Registry
SSLContextBuilder builder = SSLContexts.custom();
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
});
SSLContext sslContext = builder.build();
SchemeIOSessionStrategy sslioSessionStrategy = new SSLIOSessionStrategy(sslContext,
new HostnameVerifier(){
@Override
public boolean verify(String hostname, SSLSession session) {
return true;// TODO as of now allow all hostnames
}
});
Registry<SchemeIOSessionStrategy> sslioSessionRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create().register("https", sslioSessionStrategy).build();
PoolingNHttpClientConnectionManager ncm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry);
CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build();
asyncHttpClient.start();
#10
2
class ApacheHttpClient {
/***
* This is a https get request that bypasses certificate checking and hostname verifier.
* It uses basis authentication method.
* It is tested with Apache httpclient-4.4.
* It dumps the contents of a https page on the console output.
* It is very similar to http get request, but with the additional customization of
* - credential provider, and
* - SSLConnectionSocketFactory to bypass certification checking and hostname verifier.
* @param path String
* @param username String
* @param password String
* @throws IOException
*/
public void get(String path, String username, String password) throws IOException {
final CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(createCredsProvider(username, password))
.setSSLSocketFactory(createGenerousSSLSocketFactory())
.build();
final CloseableHttpResponse response = httpClient.execute(new HttpGet(path));
try {
HttpEntity entity = response.getEntity();
if (entity == null)
return;
System.out.println(EntityUtils.toString(entity));
} finally {
response.close();
httpClient.close();
}
}
private CredentialsProvider createCredsProvider(String username, String password) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
return credsProvider;
}
/***
*
* @return SSLConnectionSocketFactory that bypass certificate check and bypass HostnameVerifier
*/
private SSLConnectionSocketFactory createGenerousSSLSocketFactory() {
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{createGenerousTrustManager()}, new SecureRandom());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
}
private X509TrustManager createGenerousTrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] cert, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
}
}
#11
1
(I would have added a comment directly to vasekt's answer but I don't have enough reputation points (not sure the logic there)
(我会直接在vasekt的答案中添加评论,但我没有足够的声望点(不确定那里的逻辑)
Anyway... what I wanted to say is that even if you aren't explicitly creating/asking for a PoolingConnection, doesn't mean you aren't getting one.
无论如何...我想说的是,即使你没有明确地创建/要求PoolingConnection,也不意味着你没有得到它。
I was going crazy trying to figure out why the original solution didn't work for me, but I ignored vasekt's answer as it "didn't apply to my case" - wrong!
我疯狂地想弄清楚为什么原来的解决方案不适合我,但是我忽略了vasekt的答案,因为它“不适用于我的情况” - 错了!
I was staring at my stack-trace when low and behold I saw a PoolingConnection in the middle of it. Bang - I tired his addition and success!! (our demo is tomorrow and I was getting desperate) :-)
我低时盯着我的堆栈跟踪,看到我在它的中间看到了一个PoolingConnection。砰 - 我厌倦了他的加成和成功!! (我们的演示是明天,我变得绝望):-)
#12
1
Trust All Certs in Apache HTTP Client
信任Apache HTTP客户端中的所有证书
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sc);
httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
#13
0
You can use following code snippet for get the HttpClient instance without ssl certification checking.
您可以使用以下代码片段来获取没有ssl认证检查的HttpClient实例。
private HttpClient getSSLHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
LogLoader.serverLog.trace("In getSSLHttpClient()");
SSLContext context = SSLContext.getInstance("SSL");
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
context.init(null, new TrustManager[] { tm }, null);
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(context);
builder.setSSLSocketFactory(sslConnectionFactory);
PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionFactory).register("http", plainConnectionSocketFactory).build();
PoolingHttpClientConnectionManager ccm = new PoolingHttpClientConnectionManager(registry);
ccm.setMaxTotal(BaseConstant.CONNECTION_POOL_SIZE);
ccm.setDefaultMaxPerRoute(BaseConstant.CONNECTION_POOL_SIZE);
builder.setConnectionManager((HttpClientConnectionManager) ccm);
builder.disableRedirectHandling();
LogLoader.serverLog.trace("Out getSSLHttpClient()");
return builder.build();
}
#14
0
If you are using HttpClient 4.5.x
, your code can be similar to the following:
如果您使用的是HttpClient 4.5.x,您的代码可能类似于以下内容:
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,
TrustSelfSignedStrategy.INSTANCE).build();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE);
HttpClient httpClient = HttpClients.custom()
.setDefaultCookieStore(new BasicCookieStore())
.setSSLSocketFactory(sslSocketFactory)
.build();