JDBC SSL连接MySQL

最近碰到个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,没问题,

jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8

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

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,执行是正常的,

jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8&useSSL=false

如果改为useSSL=true,

jdbc:mysql://x.x.x.x:3306/test?characterEncoding=utf8&useSSL=true

则会执行错误,

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中看到自动生成的如下文件,

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,

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方式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JDBC SSL连接SQL Server

    上次碰到的是《JDBC SSL连接MySQL》,这次则是SSL连接SQL Server。

    bisal
  • Tomcat生成的session持久化到MySQL

    The default Tomcat default session storage mechanism uses temporary files. To sa...

    用户3148308
  • 故障分析 | Bad handshake,升级 5.7.28 引起的“血案”

    作为一名 DBA 碰到过升级出问题需要回退么?碰到过回退还解决不了问题么?我有幸遇到了一次凶险的升级“血案”。

    爱可生开源社区
  • JDBC访问MySQL数据库踩坑

    作为一个 Android 开发者,闲来无事,想着使用 JSP + Servlet 写一些简单的接口,然后通过前端调用接口,后端的数据库使用的是 MySQL。

    Vance大飞
  • MySQL 异常有这一篇就够了!MySQL 抛出异常的几种常见解决方式小结

    在本文中,我总结了开发过程中最为常见的几种 MySQL 抛出的异常以及如何解决,包括高版本驱动的问题、时区配置问题、SSL 连接问题等,是一篇经验总结贴,于我个...

    白鹿第一帅
  • Hive的安装及配置

    在安装hive之前,需要安装hadoop集群环境,如果没有可以查看:Hadoop分布式集群的搭建

    foochane
  • 使用jdbc连接mysql

    image.png JDBC连接MYSQL数据库: package cn.outofmemory.test;import java.sql.Connec...

    java达人
  • Hive部署及两种启动方式

    Facebook解决海量日志数据的分析而开发了Hive,后来开源给了Apache软件基金会。

    公众号guangcity
  • JDBC连接MySQL数据库

    Linux
  • Java JDBC 连接 MySQL8 数据库

    FHAdmin
  • Mysql常见问题解决

    用户1733354
  • Confluence 6 PostgreSQL 输入你的数据库细节

    在 Confluence 的设置安装向导中,将会指导你 Confluence 如何连接到你的数据库。请确定选择 "My own database"。

    HoneyMoose
  • JDBC连接数据库

    Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mysql.com/downloads/connector/j/,

    润森
  • Java连接MySQL数据库(jdbc连接数据库)

    静谧星空TEL
  • Linux 安装 logstash 并同步 MySQL 数据库

    前两篇文章分别讲了 Linux 和 Windows 环境安装 Elasticsearch,有兴趣可以点击以下链接查看: 《windows10 安装 Elasti...

    王图思睿
  • 数据仓库 Hive(内含大数据镜像下载)

    安装没成功:直接用现成的镜像 大数据Linux实验环境虚拟机镜像文件 http://dblab.xmu.edu.cn/blog/1645-2/ cloude...

    Michael阿明
  • JDBC基础入门使用

    什么是JDBC驱动? 答:数据库连接JAVA Database Connectivity java

    WeiyiGeek
  • MyBatis-01 MyBatis入门篇

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google c...

    小小工匠
  • MySQL JDBC URL常用连接参数

    十毛

扫码关注云+社区

领取腾讯云代金券