【网络请求交互异常处理】第三方更换通讯证书导致SSLHandshakeException

异常:
javax.net.ssl.SSLHandshakeException: server certificate change is restricted during renegotiation

发生了什么?为什么会出现异常?

服务端更换证书后,客户端建立的SSL/TLS连接并没有失效,在握手时使用缓存中的sessionId进行简化的握手流程,由此触发了异常。

HttpClient如何进行Https请求?

HttpClient根据不同的协议使用不同的Socket工厂创建连接,对于https会使用SSLConnectionSocketFactory.具体的SSL/TLS连接建立过程交由SSLSocketImpl处理。

建立连接后会HttpClient并不需要关注底层的数据加密,SSLSocketImpl会负责数据的读写。

如何处理?

重启机器

由于连接池的存在,等待连接报错重新建立新的连接不是一个好的选择,这可能会造成系统持续异常。如果没有其他措施,重启大法欢迎你。

禁用session

在建立连接之后使缓存失效可以避免使用简化的握手流程,不过性能影响较大,不提倡

SSLSocket.getSession().invalidate();

失效连接

既然是因为连接池的存在要重启机器,那我们可以把连接池清空。在连接池管理器PoolingHttpClientConnectionManager中有清理空闲连接的方法。

void closeIdleConnections(long idletime, TimeUnit tunit);
我们可以将idletime设置很小,就可以关闭大部分连接了。不过这样做法有些粗暴,可能会造成误伤。

连接池是可以自定义的,按需要定制自己想要的功能,如远程清空连接池,更精细一些,根据ip+port清理指定的连接。

为什么会出现这个异常?
HttpClient 是如何进行https请求的?
除了重启机器,是否还有其他应对方式?
初探Https
本文主要从源码的角度,探寻HttpClient如何进行Https请求,以及Java是如何进行SSL连接,不涉及SSL/TLS具体协议内容。

Https基础知识
Https的基础知识前辈们已经有了很好的总结,推荐几篇博文,可以学习一下。

HTTPS深入理解
HTTPS协议详解 系列
为了更好的理解下文,这里引用两个SSL/TLS握手流程,摘自 HTTPS深入理解
验证服务器握手过程

(1) 客户端通过Client Hello消息将它支持的SSL版本、加密算法、密钥交换算法、MAC算法等信息发送给SSL服务器。

(2) 服务器确定本次通信采用的版本和加密套件,并通过Server Hello消息通知给客户端。如果服务器允许客户端在以后的通信中重用本次会话,则服务器会为本次会话分配会话ID,并通过Server Hello消息发送给SSL客户端。

(3) 服务器将携带自己公钥信息的数字证书通过Certificate消息发送给客户端。

(4) 服务器发送Server Hello Done消息,通知客户端版本和加密套件协商结束,开始进行密钥交换。

(5) 客户端验证服务器的证书合法后,利用证书中的公钥加密客户端随机生成的premaster secret,并通过Client Key Exchange消息发送给SSL服务器。

(6) 客户端发送Change Cipher Spec消息,通知服务器后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。

(7) 客户端计算已交互的握手消息(除Change Cipher Spec消息外所有已交互的消息)的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给服务器。服务器利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。

(8) 同样地,SSL服务器发送Change Cipher Spec消息,通知客户端后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。

(9) 服务器计算已交互的握手消息的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给客户端。客户端利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。

(10) 客户端接收到服务器发送的Finished消息后,如果解密成功,则可以判断服务器是数字证书的拥有者,即服务器身份验证成功,因为只有拥有私钥的服务器才能从Client Key Exchange消息中解密得到premaster secret,从而间接地实现了客户端对服务器的身份验证。
重用会话的握手过程

协商会话参数、建立会话的过程中,需要使用非对称密钥算法来加密密钥、验证通信对端的身份,计算量较大,占用了大量的系统资源。为了简化SSL握手过程,SSL允许重用已经协商过的会话,具体过程为:

(1) 客户端发送Client Hello消息,消息中的会话ID设置为重用的会话的ID。

(2) 服务器如果允许重用该会话,则通过在Server Hello消息中设置相同的会话ID来应答。这样,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你的 Java 应用需要与 HTTPS 连接,那么你需要使用 Java 中的 HTTPSURLConnection 类来进行连接。如果你遇到了 "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed" 这样的异常,那么可能是因为你的应用程序没有正确配置证书。 以下是一些可能的解决方案: 1. 导入证书 将 HTTPS 服务器的证书导入到 Java 的信任存储中。可以使用 keytool 工具来完成此操作。例如: keytool -importcert -alias mycert -file mycert.cer -keystore cacerts 其中 mycert.cer 是你要导入的证书文件。 2. 禁用证书验证 在测试期间,可以将证书验证禁用。可以使用以下代码来实现: TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 请注意,这会将所有证书视为有效,包括可能被篡改的证书,因此仅在测试期间使用。 3. 使用自定义 TrustManager 你可以编写自定义 TrustManager 来验证服务器证书。通常,你需要验证证书的有效期、颁发者等信息。以下是一个简单的示例: TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { // 验证证书有效期、颁发者等信息 } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值