Java调用ssl异常(javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or ci
首发地址、原文链接:https://www.hsmus.top/202107284.html
项目中有一个HttpUtil作为客户端,当请求https的时候,会出现:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
的问题,本文用作者已有的知识认知排查并修复此问题。
目前网上的解决方案尝试之后无果,https://www.cnblogs.com/andy-alone/p/10937311.html。
https://blog.csdn.net/Wing_kin666/article/details/116449722
-1 先把解决方案放上:
public static String httpsPost(String procid, String url, String params, int timeOut) {
// Trust all CA
HttpPost httpPost = new HttpPost(url);
String result = null;
CloseableHttpClient httpClient = null;
try {
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
return true;
}
}).build();
// Set supportedProtocols
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1","TLSv1.2"}, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
// 根据默认超时限制初始化requestConfig
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeOut).setConnectTimeout(timeOut).build();
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(params, "UTF-8");//"UTF-8");
httpPost.addHeader("Content-Type", "application/json");//"application/x-www-form-urlencoded");
httpPost.setEntity(postEntity);
// 设置请求器的配置
httpPost.setConfig(requestConfig);
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (httpPost != null) {
httpPost.releaseConnection();
}
if (httpClient != null) {
httpClient.close();
}
} catch (IOException e) {
LogUtil.addProclog(procid, CommonUtil.getTrace(e) + "\r\n");
}
}
return result;
}
1. 原因分析
1. 从百度翻译之后得知具体原因为:
javax.net.ssl.SSLHandshakeException:没有合适的协议(协议被禁用或密码套件不合适)
2. 再去查阅HTTPS握手的过程:
参考资料:https://www.cnblogs.com/jjzd/p/9346260.html
2.1 SSL握手大致过程:
-
客户端发送随机数1,支持的加密方法(如RSA公钥加密)
-
服务端发送随机数2,和服务器公钥,并确认加密方法
-
客户端发送用服务器公钥加密的随机数3
-
服务器用私钥解密这个随机数3,用加密方法计算生成对称加密的**给客户端,
接下来的报文都用双方协定好的加密方法和**,进行加密
** SSL握手详细过程:**
一、客户端发出加密通信请求ClientHello
提供:
1,协议版本(如TSL1.0)
2,随机数1(用于生成对话**)
3,支持的加密方法(如RSA公钥加密)
4,支持的压缩方法
二、服务器回应SeverHello
回应内容:
1,确认使用的加密通信协议版本(TSL1.0)
2,随机数2(用于生成对话**)
3,确认加密方法(RSA)
4,服务器证书(包含非对称加密的公钥)
5,(可选)要求客户端提供证书的请求
三、客户端验证证书
如果证书不是可信机构颁布,或证书域名与实际域名不符,或者证书已经过期,就会向访问者显示一个警告,是否继续通信
四、客户端回应
证书没有问题,就会取出证书中的服务器公钥
然后发送:
1,随机数3(pre-master key,此随机数用服务器公钥加密,防止被窃听)
2,编码改变通知(表示随后的信息都将用双方商定的方法和**发送)
3,客户端握手结束通知
五、双方生成会话**
双方同时有了三个随机数,接着就用事先商定的加密方法,各自生成同一把“会话**”
服务器端用自己的私钥(非对称加密的)获取第三个随机数,会计算生成本次所用的会话**(对称加密的**),如果前一步要求客户端证书,会在这一步验证
六、服务器最后响应
服务器生成会话**后,向客户端发送:
1,编码改变通知(后面的信息都用双方的加密方法和**来发送)
2,服务器握手结束通知
至此,握手阶段全部结束,接下来客户端与服务器进入加密通信,用会话**加密内容
2.2 分析
根据以上的 2.1.2可知,这里客户端跟服务器确认加密算法是否支持,所以为了解决我们遇到的问题,就要知道服务器可以用什么算法,以便于我们在构建客户端的时候配置响应的加密算法,想要知道服务器用什么算法,我们可以在浏览器打开目标网站,在 控制台 – 安全(security) 里面查看。
在前面的代码中
// Set supportedProtocols
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1","TLSv1.2"}, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// ---------------- 以下为SSLConnectionSocketFactory的构造方法之一
public SSLConnectionSocketFactory(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final X509HostnameVerifier hostnameVerifier) {
this(Args.notNull(sslContext, "SSL context").getSocketFactory(),
supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
根据 SSLConnectionSocketFactory
的构造方法可以知道,在二个参数可以设置加密算法,本项目之前是指定了只支持new String[]{"TLSv1"}
这一种算法,但是服务器上支持的是TLSv1.2
的算法,导致算法不匹配而报错。
知道了原因之后,有两种解决方案:
- 增加一个支持的加密算法
new String[]{"TLSv1","TLSv1.2"}
- 把第二个参数设为
null
不开启加密
那么为了安全起见,第二种方式还是需要慎重考虑,本文采用了第一种方案,且成功解决此异常。
学疏才浅,有问题恳请在评论区指出~
推荐阅读
-
Java调用ssl异常,javax.net.ssl.SSLHandshakeException: No appropriate protocol
-
Java调用ssl异常(javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or ci
-
Java调用ssl出现异常:javax.net.ssl.SSLHandshakeException: No appropriate protocol
-
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites