前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDBC SSL连接MySQL

JDBC SSL连接MySQL

作者头像
bisal
发布2021-09-10 14:24:12
5.3K0
发布2021-09-10 14:24:12
举报

最近碰到个JDBC连接MySQL出现SSL错误的问题。

SSL(Secure Socket Layer:安全套接字层),利用数据加密、身份验证和消息完整性验证机制,为基于TCP等可靠连接的应用层协议提供安全性保证。

SSL协议提供的功能主要有,

1. 数据传输的机密性:利用对称密钥算法对传输的数据进行加密。

2. 身份验证机制:基于证书利用数字签名方法对服务器和客户端进行身份验证,其中客户端的身份验证是可选的。 3. 消息完整性验证:消息传输过程中使用MAC算法来检验消息的完整性。

如果用户的传输不是通过SSL的方式,那么其在网络中数据都是以明文进行传输的,而这给别有用心的人带来了可乘之机。所以,现在很多大型网站都开启了SSL功能。同样地,在我们数据库方面,如果客户端连接服务器获取数据不是使用SSL连接,那么在传输过程中,数据就有可能被窃取。

前几天同事碰到了和这个相关的问题,MySQL 5.6如下两个SSL相关的参数默认值是DISABLED,

MySQL 5.7如下两个SSL相关的参数默认值是YES,

客户端通过如下这个jdbc串连接MySQL 5.6,没问题,

代码语言:javascript
复制
jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8

但是如果连接MySQL 5.7,提示如下警告,

代码语言:javascript
复制
WARN: Establishing SSL connection without server's identity verification is not recommended. 
According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. 
For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. 
You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.

如果增加useSSL=false,执行是正常的,

代码语言:javascript
复制
jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8&useSSL=false

如果改为useSSL=true,

代码语言:javascript
复制
jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8&useSSL=true

则会执行错误,

代码语言:javascript
复制
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure


The last packet successfully received from the server was 239 milliseconds ago.  The last packet sent successfully to the server was 235 milliseconds ago.
  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
  at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
  at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
  at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
  at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:201)
  at com.mysql.jdbc.MysqlIO.negotiateSSLConnection(MysqlIO.java:4914)
  at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1663)
  at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1224)
  at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2199)
  at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2230)
  at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2025)
  at com.mysql.jdbc.ConnectionImpl.(ConnectionImpl.java:778)
  at com.mysql.jdbc.JDBC4Connection.(JDBC4Connection.java:47)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
  at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
  at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
  at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:386)
  at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330)
  at java.sql.DriverManager.getConnection(DriverManager.java:664)
  at java.sql.DriverManager.getConnection(DriverManager.java:247)
  at com.test.TestMySQL.main(TestMySQL.java:37)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
  at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
  at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
  at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
  at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
  at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478)
  at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
  at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
  at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
  at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
  at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
  at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
  at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
  at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:186)
  ... 18 more
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
  at com.mysql.jdbc.ExportControlled$X509TrustManagerWrapper.checkServerTrusted(ExportControlled.java:302)
  at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:922)
  at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460)
  ... 26 more
Caused by: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
  at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:153)
  at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
  at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292)
  at com.mysql.jdbc.ExportControlled$X509TrustManagerWrapper.checkServerTrusted(ExportControlled.java:295)
  ... 28 more

根本原因还是MySQL 5.7提高了安全连接的要求,MySQL 5.6中默认关闭SSL,因此客户端连接,不指定useSSL没事儿,但是连接MySQL 5.7,因为默认SSL打开的,所以在jdbc中未指定useSSL会提示个warning,如果在jdbc中指定useSSL=false,明确不使用SSL连接,自然没问题,但如果使用useSSL=true,是强制使用SSL连接,然而这个不仅要求数据库端ssl配置打开,还需要在客户端做一些SSL的配置,我没操作过,各位自行搜索。

如果服务器端安装了SSL,可以在data_dir中看到自动生成的如下文件,

代码语言:javascript
复制
ca.pem            -- 自签的CA证书,客户端连接也需要提供
server-key.pem    -- 服务器端私钥文件
server-cert.pem   -- 服务器端证书文件
client-key.pem    -- 客户端连接服务器端需要提供的私钥文件
client-cert.pem   -- 客户端连接服务器端需要提供的证书文件
public_key.pem    -- 私钥/公钥对的共有成员
private_key.pem   -- 私钥/公钥对的私有成员

如果用户是采用本地localhost或者socket连接数据库,那么不会使用SSL方式了,可以用\s显示当前的连接状态,如下所示,本地连接,当前连接没有在SSL安全连接中,SSL是not in use,

代码语言:javascript
复制
mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.7.32, for el7 (x86_64) using  EditLine wrapper


Connection id:          7939
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.7.32-log MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    utf8
Conn.  characterset:    utf8
UNIX socket:            /tmp/mysql.sock
Uptime:                 104 days 5 hours 30 min 3 sec


Threads: 7  Questions: 287208  Slow queries: 30  Opens: 4496  Flush tables: 8  Open tables: 1393  Queries per second avg: 0.031
--------------

如果用SSL,因为牵扯到加密的操作,对性能就可能产生一些影响,借鉴这篇博文,提供的测试数据,了解一下。测试中的服务器配置,CPU是32核心,内存是128G,SSD磁盘。为了尽量准确测试QPS,采用全内存查询,因为我们线上热点数据基本都在内存中,按照并发线程数分类:1线程、4线程、8线程、16线程、24线程、32线程、64线程,

P.S. https://www.cnblogs.com/mysql-dba/p/7061300.html

测试数据如下,

从测试数据可以发现,开启SSL后,数据库QPS平均降低了23%左右,相对还是比较影响性能的。从SSL实现方式来看,建立连接时需要进行握手、加密、解密等操作,所以耗时基本都在建立连接阶段,这对于使用短连接的应用程序可能产生更大的性能损耗,不过如果使用连接池或者长连接可能会好许多。

因此,是否采用SSL,取决于系统的安全等级和性能要求,

1. 对于非常敏感核心的数据,或者QPS本来就不高的核心数据,可以采用SSL方式保障数据安全性。

2. 对于采用短连接、要求高性能的应用,或者不产生核心敏感数据的应用,性能和可用性才是首要,建议不要采用SSL方式。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-09-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档