什么是“javax.net.ssl.SSLHandshakeException:服务器证书更改在重新协商期间受到限制”以及如何防止它?

Posted

技术标签:

【中文标题】什么是“javax.net.ssl.SSLHandshakeException:服务器证书更改在重新协商期间受到限制”以及如何防止它?【英文标题】:What means "javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation" and how to prevent it? 【发布时间】:2015-01-22 04:12:08 【问题描述】:

我们使用 Oracle jdk 1.7.0_71 和 Tomcat 7.0.55。 不幸的是,我们在服务器之间的 SSL 连接期间开始出现以下异常:

javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation

这是什么意思? 如何预防?

Tomcat重启后异常消失。

完整的堆栈:

Caused by: javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.7.0_71]
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884) ~[?:1.7.0_71]
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) ~[?:1.7.0_71]
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:266) ~[?:1.7.0_71]
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1402) ~[?:1.7.0_71]
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209) ~[?:1.7.0_71]
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:878) ~[?:1.7.0_71]
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:814) ~[?:1.7.0_71]
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016) ~[?:1.7.0_71]
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) ~[?:1.7.0_71]
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702) ~[?:1.7.0_71]
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122) ~[?:1.7.0_71]
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82) ~[?:1.7.0_71]
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140) ~[?:1.7.0_71]
        at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:506) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) ~[commons-httpclient-3.1.jar:?]
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323) ~[commons-httpclient-3.1.jar:?]
        at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.executePostMethod(CommonsHttpInvokerRequestExecutor.java:205) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.doExecuteRequest(CommonsHttpInvokerRequestExecutor.java:140) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor.executeRequest(AbstractHttpInvokerRequestExecutor.java:136) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:192) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.java:174) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:142) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        ... 160 more

【问题讨论】:

看起来您的服务器在重新协商期间发送了不同的证书,然后最初。您是否在运行时更改了证书,或者您是否配置了多个证书? 否,一个执行 SSL 握手的证书 “X”是什么意思? * 如果它是一个错误,它似乎并不是在所有情况下都得到修复。我们也在 JDK 1.8.0_40 上看到了这一点 【参考方案1】:

客户端层代码中的此错误消息是由于最近 Java 更新中的“SSL V3.0 Poodle Vulnerability - CVE-2014-3566”后代码强化所致。这是一个错误 - 如果您无法立即更新 JRE,这里有一些解决方法:

第一个选项是在建立 HTTPS 连接时强制使用 TLS 协议:

如果您可以将 HttpClient 更新到比 4.3.6 更新的版本,那么 SSLv3 将默认禁用,您的代码不应再报告此类异常。

如果您无法升级 HttpClient 版本,则必须使用此答案的代码将协议限制为 TLS:https://***.com/a/26439487/737790

对于来自 Java 7 运行时的其他 http 访问,必须设置以下系统属性

-Dhttps.protocols="TLSv1"

详情请见:Java http clients and POODLE

第二个选项是放宽客户端检查以仍然允许使用以下属性重新协商:

-Djdk.tls.allowUnsafeServerCertChange=true 
-Dsun.security.ssl.allowUnsafeRenegotiation=true

第三种选择是“改进”您的服务器证书,以根据this post in Burp forum 将集群成员的所有 IP 地址作为主题备用名称包含在内

第四个选项是在添加此证书/重新协商检查之前降级您的 Java 版本,因此在 7u41 之前(待确认)

更新这个错误行为现在已在 JDK 更新 7u85 和 8u60 中得到修复。感谢 Pada 找到 JDK-8072385 参考。

【讨论】:

我担心所有这些选项对于 JIRA 和 Confluence 中的代码更改来说都是不好的解决方法。 Apache HttpClient 4.3.6 似乎默认禁用 SSLv3,这意味着 JIRA 和 Confluence 也应该这样做。顺便说一句,SO 包含更多与 JAVA 8 相关的详细信息 !!!. 为什么选择 JIRA 和 Confluence ?我发现 Burp 也受到了影响。可能与 HttpClient 或最近发生变化的 Spring 行为有关? 据我所知,导致此问题的代码是:hg.openjdk.java.net/jdk7u/jdk7u/jdk/rev/eabde5c42157,现在看来他们已经修复了它:bugs.openjdk.java.net/browse/JDK-8072385 所以修复将包含在:7u85 和 8u60 我现在正在使用https.protocols="TLSv1" 运行 Java 8u60,但已部署的产品仍然面临此错误。肯定还没修好。 我提出了类似的问题,但我使用的是 java 1.8 和 httclient 4.4.1,并且仅使用 TLSv1.2。看看能不能帮忙-***.com/questions/37821428/…【参考方案2】:

以下代码段在以下条件下在企业环境中为我们工作;

无缝(运行时)证书更新是一项关键要求 更新应用中使用的 HTTPClient 成本太高 将 https 协议限制为“TLSv1”无效 该应用程序是一个 JNLP 服务的 java 客户端,并且“allowUnsafeServerCertChange”和“allowUnsafeRenegotiation”都不允许通过 JNLP 参数传递给客户端应用程序(我猜 JWS 会因为安全原因阻止它们)李>

在应用程序引导期间通过 System.setProperty() 调用设置“allowUnsafeServerCertChange”和“allowUnsafeRenegotiation”无效。

if (e.getCause() instanceof SSLHandshakeException) 
    logger.debug("server https certificate has been altered");
    try 
        Class<?> c = Class.forName("sun.security.ssl.ClientHandshaker");
        Field allowUnsafeServerCertChangeField = c.getDeclaredField("allowUnsafeServerCertChange");
        allowUnsafeServerCertChangeField.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(allowUnsafeServerCertChangeField, allowUnsafeServerCertChangeField.getModifiers() & ~Modifier.FINAL);
        allowUnsafeServerCertChangeField.set(null, true);
        logger.debug("client has been updated in order to support SSL certificate change (re-negotiation) on runtime.");
    
    catch (Exception ex) 
        logger.debug("client cannot be updated to support SSL certificate change (re-negotiation) on runtime. Please restart the application.", ex);
    

请注意这应该被视为一种黑客攻击(引入漏洞)并且应该在受信任的环境中使用。在走这条路之前,应该尝试 Yves 回答中的所有选项。

【讨论】:

【参考方案3】:

这也可能是由于连接配置错误,例如 haproxy 的一个或多个负载平衡目标指向错误的 IP 地址,因此 X% 的请求获得了不同的证书。

【讨论】:

我同意。但在我的上下文中,它与集群中的 LDAP/SSL ActiveDirectory 端点相关,管理员似乎不愿意在两个端点上手动部署相同的证书,因为它破坏了自动更新机制。但是您说得对,具有正确备用名称的 10 年证书是最佳选择。【参考方案4】:

我遇到这个问题是因为服务器端更新了他们的证书。在此之前,我们的客户工作正常。我们只是重新启动了我们的程序,它又恢复了正常。

【讨论】:

【参考方案5】:

我遇到了这个问题,结果是客户端在负载均衡器后面使用不同的证书调用服务。

【讨论】:

以上是关于什么是“javax.net.ssl.SSLHandshakeException:服务器证书更改在重新协商期间受到限制”以及如何防止它?的主要内容,如果未能解决你的问题,请参考以下文章

时间是什么?时间同步是什么?GPS北斗卫星授时又是什么?

什么是拉电流,什么是灌电流?什么是吸收电流 ?

在java中,OOA是什么?OOD是什么?OOP是什么?

什么是DIV,全称是什么?

什么是抢占/什么是可抢占内核?到底有什么好处呢?

什么是 JNDI?它的基本用途是什么?什么时候使用?