一次SSL握手异常,我发现JDK还有发行版区别
最近,握手我们一个多机房部署的异常服务,调用方反馈有问题,发现在调用新加坡机房时正常,行版而调用印度机房则报SSL握手异常。区别
排查花了一些时间,握手同时也积累了一些经验,异常故记录一下,发现读完本文,行版你将了解到如下内容:
SSL握手过程SSL握手异常时的区别排查思路与工具同版本的JDK,也是握手有所差异的废话不多说,往下看...
发现问题调用方调用印度机房服务时,异常报错信息如下:

这个异常是发现同事一直在看,经过一翻搜索,行版怀疑是区别JDK版本的问题,经过询问调用方,发现调用方版本是1.8.0_91-b14,于是同事打算下载此版本JDK本地测试一下。
但这个版本JDK不太好找,于是同事就问了下我,我也找了一会也没找到,于是打算从源码编译一个此版本JDK。亿华云
经过一段时间,我通过源码编译出来了这个版本的jdk,同时同事也在网上找到了一个此版本的JDK,如下:
JDK源码:https://github.com/openjdk/jdk8u ,tag选择jdk8u91-b14即可。
网上的JDK包:https://github.com/ojdkbuild/ojdkbuild/releases/download/1.8.0.91-3/java-1.8.0-openjdk-1.8.0.91-1.b14.el6.x86_64.zip
弄到1.8.0_91-b14版JDK后,我和同事都进行了测试,奇怪的是,同事网上找的JDK重现了调用方的报错,即新加坡机房正常,而印度机房SSL握手失败,但我自己编译的JDK则两个机房都正常,我们可是相同版本的JDK啊!
好家伙,现在有2个疑问了,如下:
为啥新加坡机房正常,而印度机房SSL握手报错?
为啥相同版本的JDK,自己编译的没有问题?
为啥SSL握手报错?粗略来讲,SSL握手过程如下:
客户端发送Client Hello包给服务端,其中除了包含密钥协商相关的数据外,香港云服务器还会告知自己支持的密码套件列表。
服务端收到Client Hello包后,会给客户端回复Server Hello,其中也包含了密钥协商数据,以及服务端选择了哪个密码套件。
但有一种情况是,客户端第一步发送的所有密码套件,服务端都不支持,因此服务端会回复一个SSL握手异常包,进而导致客户端失败报错。
注:密码套件,指的是加密系统将多种密码学算法混合使用,以实现多种安全需求,如TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,使用ECDHE实现密钥协商、RSA实现证书认证、AES实现加密、SHA256实现消息防篡改。
如何确认是否是上面原因呢?我进行了如下测试:
添加JVM参数-Djavax.net.debug=SSL,并调用正常的新加坡机房,看看SSL握手选择的是什么密码套件。
$ bin/java -Djavax.net.debug=SSL SgSendRequest
可以看到,客户端提供了很多密码套件,云服务器提供商服务端选择了TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,那么极有可能是印度机房不支持此密码套件,导致印度机房请求失败,可用curl确认下:
使用curl以指定密码套件DHE-RSA-AES128-GCM-SHA256访问印度机房。
$ curl -v https://in.xxx.be.srv.com --ciphers DHE-RSA-AES128-GCM-SHA256
可以发现,印度机房确实不支持此密码套件。
注:jdk密码套件名称与curl的名称稍微有点不一致,curl的可以在这里查找 https://curl.se/docs/ssl-ciphers.html
这也就是说,此JDK支持的密码学套件与印度机房支持的密码学套件没有交集,服务端无法选出一个双方都支持的密码套件,可以进一步确认下,如下:
jdk支持的密码套件可以通过SSLServerSocketFactory.getSupportedCipherSuites()获取。
$ bin/jrunscript -e "print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))"
印度机房支持的密码套件可以使用nmap扫描获取,如下:
$ nmap --script ssl-enum-ciphers -p 443 in.xxx.be.srv.com
经过我的检查,发现jdk的密码套件与印度机房的密码套件确实没有交集,印度机房只支持一些较新的密码套件,这就是调用印度机房服务时SSL握手失败的原因。
用相同的方法,我也确认了新加坡机房,发现新加坡机房的密码套件与jdk的密码套件有交集,而TLS_DHE_RSA_WITH_AES_128_GCM_SHA256就在其中。
要解决这个问题也比较容易,要么让调用方升级jdk以支持新的密码套件,要么让印度机房SRE调整SSL配置以支持旧的密码套件,我们选择了前者。
那么,还有一个问题,为啥我自己编译的同版本的JDK就没有问题呢?
为啥自行编译的JDK没有问题?有点迷惑,我用上面相同方法确认了一下我自己编译的JDK支持哪些套件,如下:
$ bin/jrunscript -e "print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))"
可以发现,我自己编译的JDK,支持ECDH系列的新密码套件,这是为啥?
为了弄清区别,我使用问题JDK进行了调试,如下:
import javax.crypto.KeyAgreement;
import java.security.NoSuchAlgorithmException;
public class EcdhTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
System.out.println(ka);
}
}在问题JDK里面,会报如下异常:
$ bin/java EcdhTest
Exception in thread "main" java.security.NoSuchAlgorithmException: Algorithm ECDH not available
at javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:184)
at EcdhTest.main(EcdhTest.java:6)有异常就好办了,只要顺着异常产生的过程调试下去即可,大概调试了如下相关方法:
sun.security.ssl.JsseJce.getKeyAgreement("ECDH")
sun.security.ec.SunEC当调试到SunEC类时,我发现在加载sunec动态库时会报错,如下:

于是,我去问题jdk目录下查找这个动态库文件,动态库文件在Linux下一般是.so结尾,如下:
$ find | grep sunec
./jre/lib/ext/sunec.jar
./jre/lib/amd64/libsunec.so_DISABLED
./jre/lib/amd64/libsunec.diz懵逼了,在这个问题JDK里,libsunec.so竟然被改名为了libsunec.so_DISABLED,而我看了下我自己编译的JDK,这个文件是没有改名的!
终于,第二个问题也找到了原因,原来是网上找的这个JDK,通过改名libsunec.so将EC系列算法禁用了。
我大概看了会那个JDK下载页面,这个JDK构建时间挺久了,是RedHat早期为CentOS6构建的一个JDK8版本,至于为啥要禁用EC系列算法,也没找到相关解释,只好就此打住。
总结这个问题在报错能被稳定重现出来时,其实就不难了,但排查思路与使用到的工具还是挺值得分享的,如下:
客户端与服务端支持的密码套件没有交集,会导致SSL握手失败。使用-Djavax.net.debug=SSL可以调试java的SSL握手过程。通过curl --ciphers指定客户端密码套件访问服务端,可以确认服务端是否支持此密码套件。通过SSLServerSocketFactory.getSupportedCipherSuites()可获取JDK支持的密码套件。使用nmap --script ssl-enum-ciphers可扫描出服务端支持的密码套件。同样版本的JDK,不同发行商发行的,也可能存在着差异。相关文章
- 摘要:PEGOST是一种密码学算法,广泛应用于数据加密和安全领域。本文将为读者介绍PEGOST算法的基本原理和应用实践,帮助读者了解并掌握这一强大的加密算法,以保护数据的安全。什...2025-11-04
“微服务架构风格是一种将单个应用程序开发为一套小型服务的方法,每个服务都在自己的进程中运行,并使用轻量级的通信机制通常是 HTTP 类型的 API)进行通信。这些服务是围绕业务能力构建的,并且可以通过2025-11-04
1. 转字符串constinput=123;console.log(input+);//123console.log(String(input));//123console.log(input.toS2025-11-04
光学预处理与计算机视觉结合,UCR学者用漩涡实现混合计算机视觉系统
在本文中,来自加州大学河滨分校机械工程系的研究者通过应用光学漩涡证明了混合计算机视觉系统的可行性。该研究为光子学在构建通用的小脑混合神经网络和开发用于大数据分析的实时硬件方面的作用提供了新见解。从医学2025-11-04如何制作U盘启动盘(简单易行的步骤帮您快速制作一枚U盘启动盘)
摘要:在今天的电脑应用中,U盘启动盘成为了一个非常重要的工具。无论是用于安装操作系统、恢复系统、进行硬盘分区等等,制作一枚U盘启动盘可以让我们的工作更加高效和便捷。本文将为您详细介绍制作...2025-11-04
本文转载自微信公众号「丙丙」,作者丙丙 。转载本文请联系丙丙公众号。从去年开始,Java程序员们换工作面试越来越难,不懂多线程,JVM,mysql,以及一些分布式的组件都不好意思出去面试。也经常听到身2025-11-04

最新评论