mysql使用jdbc连接增加ssl认证
Posted Bolgzhang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql使用jdbc连接增加ssl认证相关的知识,希望对你有一定的参考价值。
mysql使用jdbc连接增加ssl认证
1.创建用户并指定ssl连接
grant all on . to 'imooc'@'%' identified by 'imooc require SSL;
2.查看是否使用ssl
SELECT ssl_type From mysql.user Where user="imooc"
3.配置用户必须使用ssl
ALTER USER 'imooc'@'%' REQUIRE SSL;
FLUSH PRIVILEGES;
注意:%号位置可以更换为连接数据库的ip
4.取消用户使用ssl连接
update user set ssl_type='' where user='imooc';
FLUSH PRIVILEGES;
5.导入证书
使用jdk自带的keytool导入mysql的客户端证书到密钥仓库,并生成密钥文件。
根据上文查到的ca.pem,将其复制到目标主机上,然后执行下述指令
keytool -import -trustcacerts -v -alias Mysql -file "C:\\ProgramData\\MySQL\\MySQL Server 8.0\\Data\\ca.pem" -keystore "mysql.ks"
设置密钥并记住密钥
导入成功后
扩展:
#1: ObjectId: 2.5.29.19 Criticality=true //这里为true
BasicConstraints:[
CA:true //这里为true
PathLen:2147483647
]
注意:C:\\ProgramData\\MySQL\\MySQL Server 8.0\\Data\\ca.pem为ca证书的路径,mysql
6.验证证书是否导入
keytool -list -keystore mysql.ks
导入成功后:
密钥库类型: jks
密钥库提供方: SUN
您的密钥库包含 1 个条目
mysql, 2022-2-23, trustedCertEntry,
证书指纹 (SHA1): CB:E2:5C:87:4E:93:62:8F:97:F9:7A:4B:0C:F3:6D:4D:63:DB:52:AB
7.将证书放在目标服务器或者http服务器,更改mysql驱动和连接配置
driverClassName=com.mysql.cj.jdbc.Driver
"jdbc:mysql://124.222.101.203:3306/imooc?useUnicode=true&useSSL=true&trustCertificateKeyStorePassword=123456&serverTimezone=Asia/Shanghai&trustCertificateKeyStoreUrl=http://localhost:8080/mysql.ks
注意:124.222.101.203为数据库服务器地址,trustCertificateKeyStorePassword=你设置的密钥,trustCertificateKeyStoreUrl=当前服务器可访问到证书的地址,useSSL=true,verifyServerCertificate=true代表需要客户端密钥库和信任库
8.数据库加密,客户端不使用证书
jdbc:mysql://124.222.101.203:3306/imooc?allowMultiQueries=true&useUnicode&characterEncoding=UTF-8&autoReconnect=true&useSSL=true&verifyServerCertificate=false&requireSSL=true",
注意:verifyServerCertificate=false不需要验证客户端密钥
9.数据库加密,客户端服务端双向验证(建立在数据库开启ssl认证并且生成服务端和客户端证书)
设置服务器身份验证:导入服务器证书
keytool -importcert -alias MySQLCACert -file ca.pem -keystore truststore.jks -storepass 123456
设置客户端身份验证:
将客户端密钥和证书文件转换为 PKCS #12 存档:(在数据库服务器生成)
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -name "mysqlclient" -passout pass:123456 -out client-keystore.p12
将客户端密钥和证书导入 Java 密钥库:
keytool -importkeystore -srckeystore client-keystore.p12 -srcstoretype pkcs12 -srcstorepass 123456 -destkeystore keystore.jks -deststoretype JKS -deststorepass 123456
java数据库连接字符串:
"jdbc:mysql://124.222.101.203:3306/imooc?"
+ "useSSL=true"
+ "&verifyServerCertificate=true"
+ "&requireSSL=true"
+ "&trustCertificateKeyStoreUrl=file:D:/ssl.132/truststore.jks"
+ "&trustCertificateKeyStorePassword=mypassword"
+ "&clientCertificateKeyStoreUrl=file:D:/ssl.132/keystore.jks"
+ "&clientCertificateKeyStorePassword=mypassword",
注意:123456为密码
10.导入jks证书
使用jdk自带的keytool导入mysql的客户端证书到密钥仓库,并生成密钥文件。
根据上文查到的ca.pem,将其复制到目标主机上,然后执行下述指令
keytool -importcert -alias MySQLCACert -file ca.pem -keystore truststore.jks -storepass 123456 -noprompt
注意:123456为密码,ca.pem可替换为路径
11.验证证书是否导入
keytool -v -list -keystore truststore.jks -storepass "123456"
导入成功后:
密钥库类型: jks
密钥库提供方: SUN
您的密钥库包含 1 个条目
mysql, 2022-2-23, trustedCertEntry,
证书指纹 (SHA1): CB:E2:5C:87:4E:93:62:8F:97:F9:7A:4B:0C:F3:6D:4D:63:DB:52:AB
12.将证书放在目标服务器或者http服务器,更改mysql驱动和连接配置
注意:mysql连接驱动为mysql-connect-8.0.16以上版本,8.0.16以下版本使用ssl连接会出现日志报错问题,需升级解决
driverClassName=com.mysql.cj.jdbc.Driver
"jdbc:mysql://124.222.101.203:3306/imooc?useUnicode=true&useSSL=true&trustCertificateKeyStorePassword=123456&serverTimezone=Asia/Shanghai&trustCertificateKeyStoreUrl=http://localhost:8080/truststore.jks
注意:124.222.101.203为数据库服务器地址,trustCertificateKeyStorePassword=你设置的密钥,trustCertificateKeyStoreUrl=当前服务器可访问到证书的地址,useSSL=true,verifyServerCertificate=true代表需要客户端密钥库和信任库
13.useSSL=false和true的区别:
SSL(Secure Sockets Layer 安全套接字协议),在mysql进行连接的时候,如果mysql的版本是5.7之后的版本必须要加上useSSL=false,mysql5.7以及之前的版本则不用进行添加useSSL=false,会默认为false,一般情况下都是使用useSSL=false,尤其是在将项目部署到linux上时,一定要使用useSSL=false!!!,useSSL=true是进行安全验证,一般通过证书或者令牌什么的,useSSL=false就是通过账号密码进行连接,通常使用useSSL=false!!!
14.附上jdbc连接mysql数据库的代码:
//mysql使用ssl方式jdbc连接数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 标准JDBC操作五步骤
*/
public class StandardJDBCSample
public static void main(String[] args)
Connection conn = null;
try
//1. 加载并注册JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 创建数据库连接
conn = DriverManager.getConnection(
//无需证书: "jdbc:mysql://124.222.101.203:3306/imooc?allowMultiQueries=true&useUnicode&characterEncoding=UTF-8&autoReconnect=true&useSSL=true&verifyServerCertificate=false&requireSSL=true",
//客户端证书 "jdbc:mysql://124.222.101.203:3306/imooc?useUnicode=true&useSSL=true&verifyServerCertificate=true&trustCertificateKeyStorePassword=123456&serverTimezone=Asia/Shanghai&trustCertificateKeyStoreUrl=http://localhost:8080/mysql.ks",
//客户端证书 "jdbc:mysql://124.222.101.203:3306/imooc?useUnicode=true&useSSL=true&verifyServerCertificate=true&trustCertificateKeyStorePassword=Truststore@123&serverTimezone=Asia/Shanghai&trustCertificateKeyStoreUrl=http://localhost:8080/truststore.jks",
"jdbc:mysql://124.222.101.203:3306/imooc?useUnicode=true&serverTimezone=Asia/Shanghai&useSSL=true",
"imooc", "imooc"
);
//3. 创建Statement对象
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from employee where dname='市场部'");
//4. 遍历查询结果
while (rs.next())
Integer eno = rs.getInt(1); //eno
String ename = rs.getString("ename");
Float salary = rs.getFloat("salary");
String dname = rs.getString("dname");
System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
catch(Exception e)
e.printStackTrace();
finally
try
if (conn != null && conn.isClosed() == false)
//5. 关闭连接,释放资源
conn.close();
catch(Exception ex)
ex.printStackTrace();
15.数据库sql文件和jar包的链接:
链接:https://pan.baidu.com/s/1OmlrnE3ii58rtzdVl91Y7g
提取码:6yo2
需要联系博主
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.<init>(ConnectionImpl.java:778)
at com.mysql.jdbc.JDBC4Connection.<init>(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方式。
近期更新的文章:
文章分类和索引:
以上是关于mysql使用jdbc连接增加ssl认证的主要内容,如果未能解决你的问题,请参考以下文章
与 SSL 的 mysql jdbc 连接在 tls 握手级别失败
jdbc连接sqlserver2008时报错 "驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接"