首页 > 百科知识 正文

Connector升级引发连接失败的排查之路,mysql突然连接失败

时间:2024-03-20 22:00:01 阅读:675 作者:秂沒狗衷铖

作者介绍

农行研发中心“数风云”团队,一支朝气蓬勃、快速成长的技术团队,始终致力于农行大数据、数据库和云计算等领域的应用实践与技术创新,探索数据赋能,勇攀数据云巅,为企业数字化转型和金融科技发展不断贡献力量。

郭斌斌,爱可生DBA团队成员,负责MySQL数据库、爱可生云树DMP产品的日常运维,擅长数据库故障处理。对开源数据库MySQL、Redis有浓厚兴趣。

一、现象

在IBM jdk1.8.0环境上将mysql-connector-java-8.0.18升级至8.0.20后报错:“javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)”,报错详见图1。在openjdk 1.8版本上升级MySQL驱动后能正常连接。

Connector升级引发连接失败的排查之路,mysql突然连接失败-第1张

图1. IBM jdk1.8环境MySQL驱动升级后连接失败

初步分析为IBM jdk1.8版本中支持的协议或加密套件(Cipher suites)老旧导致SSL连接握手失败。

二、分析

1、官网资料分析

(1)MySQL支持的协议和套件

经查官网,MySQL驱动尝试连接MySQL 8.0时会尝试使用TLS版本:TLSv1,TLSv1.1,TLSv1.2,TLSv1.3。驱动TLS配置文件TlsSettings.properties(自8.0.19版本新增,详见“2.1.2 MySQL驱动更新说明”)中Cipher suites均以TLS开头,如图2。官网地址:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-using-ssl.html。

Connector升级引发连接失败的排查之路,mysql突然连接失败-第2张

图2. MySQL驱动TLS配置文件

(2)MySQL驱动更新说明

继续查看官网MySQL驱动发版说明,mysql connector-java-8.0.18之后8.0.19和8.0.20的变更发现:从8.0.19开始,驱动使用的Cipher suites预先在一个配置文件中进行了限制,该配置文件及目录:src/main/resources/com/mysql/cj/TlsSettings.properties(官网地址:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-binary-installation.html)。经查验8.0.19和8.0.20均能找到该配置文件,而8.0.18版本没有该配置文件。

(3)IBM JSSE2支持的协议和套件

继续翻IBM官网,IBM JSSE2默认支持协议: SSL,TLS, TLSv1, TLSv1.1,TLSv1.2。部分Cipher suites在ORACLE中以“TLS”开头,而在IBM SDK中以”SSL”开头。IBM官网显示的53个Cipher suites中49个以SSL开头,4个以TLS开头。文档提示可以通过 将系统参数com.ibm.jsse2.overrideDefaultCSName设置为true(默认为false)使得IBM JDK中cipher suite名称与ORACLE匹配。文档解释这个差异是由于部分套件在TSL规范首次发布之前就已命名。

官网链接:

https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jsse2Docs/ciphersuites.html

Connector升级引发连接失败的排查之路,mysql突然连接失败-第3张

2、抓包分析

(1)IBM jdk1.8 mysql-connector-java-8.0.20

编写脚本采用jdbc连接数据库,使用java -verbose, 获取class loader顺序,使用 java -Djavax.net.debug=true 查看 TLS 的信息:

javax.net.ssl|FINE|01|main|2021-03-30 11:47:33.493 UTC|Thread.java:1164|No available cipher suite for TLS13 javax.net.ssl|FINE|01|main|2021-03-30 11:47:33.493 UTC|Thread.java:1164|No available cipher suite for TLS12 javax.net.ssl|FINE|01|main|2021-03-30 11:47:33.493 UTC|Thread.java:1164|No available cipher suite for TLS11 javax.net.ssl|FINE|01|main|2021-03-30 11:47:33.494 UTC|Thread.java:1164|No available cipher suite for TLS10

日志中可看到依次尝试使用TLS13、TLS12、TLS11、TLS10协议,但没有可用的加密套件(cipher suite)。

(2)IBM jdk1.8 mysql-connector-java-8.0.20 com.ibm.jsse2.overrideDefaultCSName=true

通过脚本中添加参数com.ibm.jsse2.overrideDefaultCSName=true显示连接MySQL成功。添加javax.net.debug=true观察SSL的握手阶段:

javax.net.ssl|FINE|01|main|2021-03-30 14:13:29.736 UTC|Thread.java:1164|Consuming ServerHello handshake message ( "ServerHello": { "server version" : "TLSv1.2", "random" : "33 17 60 BC C2 2E 3B D3 AA 40 E3 AC 8E EB 6B B8 8B 69 44 4B 3C 1F 2C F0 44 4F 57 4E 47 52 44 01", "session id" : "7C 9E C9 73 9A 3B F1 5E D4 0D D7 7F B5 55 5A 34 B3 08 F3 1F 30 37 84 2F 5E 9D B0 52 8B 62 DA 13", "cipher suite" : "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030)", "compression methods" : "00", "extensions" : [ "renegotiation_info (65,281)": { "renegotiated connection": [<no renegotiated connection>] }, "ec_point_formats (11)": { "formats": [uncompressed, ansiX962_compressed_prime, ansiX962_compressed_char2] }, "extended_master_secret (23)": { <empty> } ] }

通过日志可见握手阶段选择了TLSv1.2和cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384。

(3) IBM jdk1.8 mysql-connector-java-8.0.18

用javax.net.debug=true观察mysql-connector 8.0.18的表现:

Produced ClientHello handshake message ( "ClientHello": { "client version" : "TLSv1.2", "random" : "B6 0B CF 14 D5 3F 42 00 B5 5C 11 61 CA F7 E0 FD 8E F3 82 DC 96 F1 30 47 80 EC 7D A6 29 FC 44 9A", "session id" : "", "cipher suites" : "[SSL_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), SSL_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), SSL_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), SSL_RSA_WITH_AES_256_GCM_SHA384(0x009D), SSL_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), SSL_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), SSL_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), SSL_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), SSL_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), SSL_RSA_WITH_AES_128_GCM_SHA256(0x009C), SSL_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), SSL_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), SSL_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), SSL_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), SSL_RSA_WITH_AES_256_CBC_SHA256(0x003D), SSL_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), SSL_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), SSL_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), SSL_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), SSL_RSA_WITH_AES_256_CBC_SHA(0x0035), SSL_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), SSL_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), SSL_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), SSL_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), SSL_RSA_WITH_AES_128_CBC_SHA256(0x003C), SSL_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), SSL_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), SSL_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), SSL_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), SSL_RSA_WITH_AES_128_CBC_SHA(0x002F), SSL_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), SSL_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), SSL_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), SSL_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]", "compression methods" : "00", "extensions" : [ "supported_groups (10)": { "versions": [secp256r1, secp384r1, secp521r1] }, "ec_point_formats (11)": { "formats": [uncompressed] }, "signature_algorithms (13)": { "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1] }, "signature_algorithms_cert (50)": { "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1] }, "extended_master_secret (23)": { <empty> }, "supported_versions (43)": { "versions": [TLSv1.2, TLSv1.1, TLSv1] } ] } )

可以看到MySQL connector 8.0.18在建立TLS连接时, 就已经选择了TLSv1.2和cipher suite列表,列表中大部分cipher suite以“SSL”开头。

3、结论

通过官网资料和抓包分析,MySQL connector 8.0.18未对cipher suite作TLS限制,故能连接成功。当驱动升级至MySQL connector 8.0.19或8.0.20版本,MySQL对cipher suite进行了限制,且均以TLS开头,而IBM JSSE2大部分套件还保持以SSL开头的命名,故而导致连接握手时因没有可用套件而失败。

三、方案

由于本次驱动升级是在IBM WAS环境上进行,还需要在WAS环境上验证。

1、方案1

建议IBM jdk升级版本兼容MySQL协议和加密套件,经与厂商确认此方案暂不可行。

2、方案2

依据IBM官方文档建议将系统参数com.ibm.jsse2.overrideDefaultCSName设置为true,在IBM jdk1.8.0_281 MySQL connector 8.0.20上通过脚本调用方式连接成功。

经咨询IBM厂商,参数com.ibm.jsse2.overrideDefaultCSName是java 1.8.0_211开始才有的,对应用是否有影响取决于应用如何用SSL,如果用WAS的配置则没有关系,如果用自己的,需检查code里是否定义了cipher用SSL还是TLS开头。该参数在WAS中配置过程如下:

服务器-》您的服务器-》进程定义-》java虚拟机-》定制属性,添加:

  • 名字:com.ibm.jsse2.overrideDefaultCSName
  • 值:true

保存配置后同步,重新启动生效。

本方法经项目组在WAS9.0.5.5 jdk 1.8.0_211环境上验证并未生效。最终通过将WAS环境上jdk升级到1.8.0_281,并使用com.ibm.jsse2.overrideDefaultCSName=true,才生效。

WAS9已经将WAS和jdk分开,可单独升级jdk,不用升级WAS版本。

3、方案3

jdbc连接带上参数useSSL=false和allowPublicKeyRetrieval=true,连接成功。本方案作为IBM jdk升级之前的缓释方案供项目组临时采用。

配置参数AllowPublicKeyRetrieval=True,可能会导致恶意代理通过中间人攻击(MITM)获取到明文密码,所以,JDBC默认关闭该参数,需谨慎开启。

题外话:若仅配置useSSL=false,未配置AllowPublicKeyRetrieval=True时,当MySQL服务端应用用户认证缓存失效时,应用端可能会出现Public Key Retrieval is not allowed的错误无法连接数据库。此情况需确保数据库服务端应用用户认证缓存不失效(即在MySQL服务端应用用户缓存失效操作后,进行一次应用用户认证登录)。

4、方案4

在IBM厂商建议下,如果jdk不升级,继续使用JDK 1.8.0_211,尝试使用如下参数:

JVM通用参数里设置:

-Dcom.unboundid.util.SSLUtil.defaultSSLProtocol=TLSV1.2 -Dcom.unboundid.util.SSLUtil.enabledSSLProtocols=TLSV1.2

经以上方案验证:方案4未生效,方案3为临时缓释措施,最终采用了升级jdk com.ibm.jsse2.overrideDefaultCSName=true的方案2。

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

关注公众号【dbaplus社群】,获取更多原创技术文章和精选工具下载

版权声明:该问答观点仅代表作者本人。如有侵犯您版权权利请告知 cpumjj@hotmail.com,我们将尽快删除相关内容。