版本说明
httpclinet:4.3.1 jdk:1.6 tomcat:6
异常信息
Caused by: javax.net.ssl.SSLException: Certificate for <**> doesn't contain CN or DNS subjectAlt
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:178)
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:152)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:133)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:291)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:262)
at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:118)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:357)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:218)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
... 18 more
背景
使用httpclient忽略证书发起https请求,代码如下
package cn.org.pcac.ries.httpService.util;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class HttpsSend {
public static void main(String[] args) throws Exception {
String url = "";
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
HttpPost httpPost = new HttpPost(url);
// 设置客户超时
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setSocketTimeout(9000).setConnectTimeout(9000)
.setConnectionRequestTimeout(9000)
.setStaleConnectionCheckEnabled(true).build();
// 设置服务端
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
.build();
formparams.add(new BasicNameValuePair("param", ""));
httpPost.setConfig(requestConfig);
CloseableHttpClient httpclient = null;
httpclient = HttpClients.custom()
.setDefaultRequestConfig(defaultRequestConfig).build();
SSLContext sslcontext = null;
if (url.indexOf("https") == 0) {
sslcontext = createIgnoreVerifySSL();
httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig)
.setSslcontext(sslcontext).build();
}
UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formparams,
"UTF-8");
httpPost.setEntity(uefEntity);
HttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (entity != null) {
// 获得返回报文
String respons = EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
System.out.println(respons);
}
}
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("TLS");
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
}
错误原因
跟踪源码,异常信息如下所示: 访问网站的证书为自签证书,缺少CN=等信息,但是我已经忽略证书校验了为什么还会出现这个问题呢? 发现初始化CloseableHttpClient时,有如下代码: 因此修改初始化CloseableHttpClient,将 httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig) .setSslcontext(sslcontext).build(); 改成 httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig) .setHostnameVerifier(hostnameVerifier) .setSslcontext(sslcontext).build(); 增加变量 public static X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; }
@Override
public void verify(String host, String[] cns, String[] subjectAlts)
throws SSLException {
}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {
}
@Override
public void verify(String host, SSLSocket ssl) throws IOException {
}
};