农行研发中心“数风云”团队,一支朝气蓬勃、快速成长的技术团队,始终致力于农行大数据、数据库和云计算等领域的应用实践与技术创新,探索数据赋能,勇攀数据云巅,为企业数字化转型和金融科技发展不断贡献力量。
郭斌斌,爱可生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驱动后能正常连接。
图1. IBM jdk1.8环境MySQL驱动升级后连接失败
初步分析为IBM jdk1.8版本中支持的协议或加密套件(Cipher suites)老旧导致SSL连接握手失败。
(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。
图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
(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”开头。
通过官网资料和抓包分析,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环境上验证。
建议IBM jdk升级版本兼容MySQL协议和加密套件,经与厂商确认此方案暂不可行。
依据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版本。
jdbc连接带上参数useSSL=false和allowPublicKeyRetrieval=true,连接成功。本方案作为IBM jdk升级之前的缓释方案供项目组临时采用。
配置参数AllowPublicKeyRetrieval=True,可能会导致恶意代理通过中间人攻击(MITM)获取到明文密码,所以,JDBC默认关闭该参数,需谨慎开启。
题外话:若仅配置useSSL=false,未配置AllowPublicKeyRetrieval=True时,当MySQL服务端应用用户认证缓存失效时,应用端可能会出现Public Key Retrieval is not allowed的错误无法连接数据库。此情况需确保数据库服务端应用用户认证缓存不失效(即在MySQL服务端应用用户缓存失效操作后,进行一次应用用户认证登录)。
在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
如果字段的最大可能长度超过255字节,那么长度值可能…
只能说作者太用心了,优秀
感谢详解
一般干个7-8年(即30岁左右),能做到年入40w-50w;有…
230721