目录
1. 情景描述:
2. 解决方法:
方法一:换jdk1.8
方法二:在创建SSLConnectionSocketFactory 时指定协议
参考网址:
请教一个 Apache HttpClient 中 SSLConnectionSocketFactory 的 supportedProtocols 的问题 - V2EX
https://www.v2ex.com/t/615059
记一次HttpClient+jdk8调用SSLv3接口的问题 - 柚子苹果果 - 博客园
https://www.cnblogs.com/LOVE0612/p/13445704.html
HttpClient4.3 关于https 中SSL证书请求问题_游龙YoooLong-CSDN博客_sslconnectionsocketfactory
https://blog.csdn.net/sleeping_/article/details/50500351
访问第三方https接口报错:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
开发环境:jdk1.7.0_60 + httpclient4.5.3
第三方接口url:https://posuat1.mercedes-benz-finance.com.cn/EKYC_ELICENSE/e-license
具体报错信息:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 。。。。。。。。。。。。。。。。。。。。 |
尝试将代码在jdk1.8.0_161 上运行,发现没有报错,可以正常访问上述https网址。
public static CloseableHttpClient createSSLClientDefault(){
// TLSv1 TLSv1.1 TLSv1.2
// System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
try {
//SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
// 在JSSE中,证书信任管理器类就是实现了接口X509TrustManager的类。
//我们可以自己实现该接口,让它信任我们指定的证书。
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
//信任所有
X509TrustManager x509mgr = new X509TrustManager() {
//该方法检查客户端的证书,若不信任该证书则抛出异常
public void checkClientTrusted(X509Certificate[] xcs, String string) {
}
//该方法检查服务端的证书,若不信任该证书则抛出异常
public void checkServerTrusted(X509Certificate[] xcs, String string) {
}
//返回受信任的X509证书数组。
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
// sslContext.init(null, new TrustManager[] { x509mgr }, null);
sslContext.init(null, new TrustManager[] { x509mgr }, new java.security.SecureRandom());
/*
System.out.println("缺省安全套接字使用的协议: " + sslContext.getProtocol());
// 获取SSLContext实例相关的SSLEngine
SSLEngine en = sslContext.createSSLEngine();
System.out.println("支持的协议: " + Arrays.asList(en.getSupportedProtocols()));
System.out.println("启用的协议: " + Arrays.asList(en.getEnabledProtocols()));
System.out.println("支持的加密套件: " + Arrays.asList(en.getSupportedCipherSuites()));
System.out.println("启用的加密套件: " + Arrays.asList(en.getEnabledCipherSuites()));
*/
创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"},
null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
// sslContext,
// new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"},
// null,
// NoopHostnameVerifier.INSTANCE);
// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
// sslContext,
// new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"},
// null,
// NoopHostnameVerifier.INSTANCE);
// HttpsURLConnection对象就可以正常连接HTTPS了,无论其证书是否经权威机构的验证,只要实现了接口X509TrustManager的类MyX509TrustManager信任该证书。
return HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfig).build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// 创建默认的httpClient实例.
return HttpClients.createDefault();
}
(1)上面的代码中,主要是在 创建 SSLConnectionSocketFactory sslsf 时,指定了协议:
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE); |
(2)上面的代码中,有三个创建 SSLConnectionSocketFactory sslsf 的地方(其中有两个被注释掉了),区别在于指定的协议不同,以及最后一个参数不同。但是针对上面的那个https的url,这三种创建方式都能够正常访问。