项目场景:
提示:本地调试正常: 项目场景: 部署到WebSphere服务器上就会报上述错误; 一度认为是WebSphere服务器上的配置有问题,经过多次偿试,最终解决问题发现和服务配置无关; 测试环境使用HttpClient发送https请求下载附件时报错:
问题描述
提示:项目地址是http,需要访问的地址是https:
因为访问https地址所以默认信任所有证书:
public static CloseableHttpClient createSSLClientDefault() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return HttpClients.createDefault();
}
使用httpclient发送https请求下载附件时报错:
javax.net.ssl.SSLHandshakeException: Received fatal alert: unrecognized_name
at com.ibm.jsse2.i.a(i.java:31)
~[?:8.0 build 201512221
at com.ibm.jsse2.i.ali.java:43)~?:8.0 build 201512221
at com.ibm.jsse2.as.blas.java:816) -?:8.0 build 201512221
at com.ibm.jsse2.as.alas. java: 752)
~?:8.0 build 201512221
at
com.ibm.jsse2.as.i(as.java:130)
~?:8.0 build 201512221
at
com.ibm.jssez.as.a(as.java:483) ~ ?:8.0 build 201512221
com.ibm.jsse2.as.startHandshake(as.java:160)
~[?:8.0 build 201512221
附图: 此处看报错信息曾怀疑是服务器使用的是ibmjdk导致的错误,但是后续解决问题之后证实这个方向是错误的
原因分析:
https认证方式分为2种(单向认证、双向认证):
单向认证:
单向认证一般是指客户端确认服务端身份(也就是我常用的不安全认证模式) 上面代码也确实证实了单向认证请求https是没有问题的;
双向认证:
双向认证则是指在客户端需要确认服务端身份的同时,服务端也需要确认客户端的身份。 接下来也是我解决此错误的原因
网上搜索到的解决方案,偿试无效的有
一、设置系统属性,在启动类加上下列代码无效:
System.setProperty ("jsse.enableSNIExtension", "false");
二、在JVM启动命令中加入指令无效: -Djsse.enableSNIExtension=false
三、将上面指令配置到tomcat中(没有偿试过) 最终也不是通过此方案解决错误
解决方案:
请求双向认证的https地址时,客户端需要初始化证书及证书版本,客户端会根据根证书生成携带公钥的子证书发服务端发送二次握手,服务端会验证客户端的请求是否合法,至此问题解决.代码如下:
public static CloseableHttpClient creatTwoWayHttpClient() {
try {
CloseableHttpClient httpclient;
SSLContext ctx = SSLContexts.custom().useProtocol("TLSv1.2").build();
httpclient = HttpClientBuilder.create().setSslcontext(ctx).build();
return httpclient;
} catch (Exception e) {
e.printStackTrace();
}
return HttpClients.createDefault();
}
暂未实现 单向验证和双向验证请求兼容初始化客户端代码,只是在使用时加了一个参数区分;代码如下:
public static CloseableHttpClient createSSLClientDefault(Boolean isTwoWayAuthentication) {
try {
if (isTwoWayAuthentication) {
return creatTwoWayHttpClient();
}
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return HttpClients.createDefault();
}
|