一、概述
MySQL 服务器和客户端之间的未加密连接可能会暴露通过网络传输的数据。对于生产就绪的应用程序,我们应该通过TLS(传输层安全)协议将所有通信转移到安全连接。
在本教程中,我们将学习如何在MySQL 服务器上启用安全连接。此外,我们将配置Spring Boot 应用程序以使用此安全连接。
2. 为什么在MySQL 上使用TLS?
首先,让我们了解一些TLS 的基础知识。
TLS 协议使用加密算法来确保通过网络接收到的数据是可信的,并且不会被篡改或检查。它具有检测数据更改、丢失或重放攻击的机制。TLS 还包含使用X.509 标准提供身份验证的算法。
加密连接增加了一层安全性,使数据无法通过网络流量读取。
在MySQL 服务器和客户端之间配置安全连接可以实现更好的身份验证、数据完整性和可信度。此外,MySQL 服务器可以对客户端的身份执行额外的检查。
但是,这种安全连接会因加密而带来性能损失。性能成本的严重程度取决于各种因素,例如查询大小、数据负载、服务器硬件、网络带宽和其他因素。
3. 在MySQL 服务器上配置TLS 连接
MySQL 服务器在每个连接的基础上执行加密,对于给定的用户,这可以是强制性的或可选的。MySQL 通过安装的OpenSSL 库在运行时支持与SSL 加密相关的操作。
在初始握手之后,我们可以使用JDBC Driver Connector/J对客户端和服务器之间的数据进行加密。
MySQL 服务器v8.0.28 或更高版本仅支持TLS v1.2 和TLS v1.3。它不再支持早期版本的TLS(v1 和v1.1)。
可以使用由受信任的根证书颁发机构签名的证书或自签名证书来启用服务器身份验证。此外,为MySQL 构建我们自己的根CA 文件是常见的做法,即使在生产中也是如此。
此外,服务器可以验证和验证客户端的SSL 证书,并对客户端的身份进行额外检查。
3.1。使用TLS 证书配置MySQL 服务器
我们将使用属性require_secure_transport
和默认生成的证书在MySQL 服务器上启用安全传输。
让我们通过在docker-compose.yml
中实现设置来快速引导MySQL 服务器:
version: '3.8'
services:
mysql-service:
image: "mysql/mysql-server:8.0.30"
container_name: mysql-db
command: [ "mysqld",
"--require_secure_transport=ON",
"--default_authentication_plugin=mysql_native_password",
"--general_log=ON" ]
ports:
- "3306:3306"
volumes:
- type: bind
source: ./data
target: /var/lib/mysql
restart: always
environment:
MYSQL_ROOT_HOST: "%"
MYSQL_ROOT_PASSWORD: "Password2022"
MYSQL_DATABASE: test_db
我们应该注意,上面的MySQL 服务器使用位于路径/var/lib/mysql
中的默认证书.
或者,我们可以通过在docker-compose.yml
中包含一些mysqld
配置来覆盖默认证书:
command: [ "mysqld",
"--require_secure_transport=ON",
"--ssl-ca=/etc/certs/ca.pem",
"--ssl-cert=/etc/certs/server-cert.pem",
"--ssl-key=/etc/certs/server-key.pem",
....]
现在,让我们使用the docker-compose
命令启动mysql-service
:
$ docker-compose -p mysql-server up
3.2.使用X509
创建用户
或者,我们可以使用X.509 标准为MySQL 服务器配置客户端标识。对于X509
,需要有效的客户端证书。这启用了双向双向TLS 或mTLS
。
让我们使用X509
创建一个用户并授予对test_db
数据库的权限:
mysql> CREATE USER 'test_user'@'%' IDENTIFIED BY 'Password2022' require X509;
mysql> GRANT ALL PRIVILEGES ON test_db.* TO 'test_user'@'%';
我们可以在没有任何用户证书标识的情况下建立TLS 连接:
mysql> CREATE USER 'test_user'@'%' IDENTIFIED BY 'Password2022' require SSL;
我们应该注意,如果使用SSL,客户端需要提供信任库。
4. 在Spring Boot 应用程序上配置TLS
Spring Boot 应用程序可以通过使用一些属性设置JDBC URL 来配置JDBC 连接上的TLS。
有多种方法可以配置Spring Boot 应用程序以将TLS 与MySQL一起使用。
在此之前,我们需要将信任库和客户端证书转换为JKS
格式。
4.1。将PEM 文件转换为JKS 格式
让我们将MySQL 服务器生成的ca.pem
和client-cert.pem
文件转换为JKS
格式:
keytool -importcert -alias MySQLCACert.jks -file ./data/ca.pem \
-keystore ./certs/truststore.jks -storepass mypassword
openssl pkcs12 -export -in ./data/client-cert.pem -inkey ./data/client-key.pem \
-out ./certs/certificate.p12 -name "certificate"
keytool -importkeystore -srckeystore ./certs/certificate.p12 -srcstoretype pkcs12 -destkeystore ./certs/client-cert.jks
我们应该注意到,从Java 9 开始,默认的密钥库格式是PKCS12
。
4.2.使用application.yml
配置
可以通过将sslMode
设置为PREFERRED
、REQUIRED
、VERIFY_CA
或VERIFY_IDENTITY
来启用TLS。
PREFERRED
模式要么使用安全连接,如果服务器支持它,或者以其他方式回退到未加密的连接。
使用REQUIRED mode
,客户端只能使用加密连接。与REQUIRED
一样,VERIFY_CA
模式使用安全连接,但另外根据配置的证书颁发机构(CA) 证书验证服务器证书。
The VERIFY_IDENTITY
模式对主机名进行额外的检查以及证书验证。
此外,需要将一些Connector/J
属性添加到JDBC URL,例如trustCertufucateKeyStoreUrl
、trustCertificateKeyStorePassword
、clientCertificateKeyStoreUrl
和clientCertificateKeyStorePassword
。
让我们在application.yml
中配置JDBC URL,并将sslMode
设置为VERIFY_CA
:
spring:
profiles: "dev2"
datasource:
url: >-
jdbc:mysql://localhost:3306/test_db?
sslMode=VERIFY_CA&
trustCertificateKeyStoreUrl=file:/<project-path>/mysql-server/certs/truststore.jks&
trustCertificateKeyStorePassword=mypassword&
clientCertificateKeyStoreUrl=file:/<project-path>/mysql-server/certs/client-cert.jks&
clientCertificateKeyStorePassword=mypassword
username: test_user
password: Password2022
我们应该注意,等同于**VERIFY_CA
的已弃用属性是useSSL=true
和verifyServerCertificate=true
的组合**。
如果未提供信任证书文件,我们将收到一个错误:
Caused by: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
at java.base/sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:157) ~[na:na]
at java.base/sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:83) ~[na:na]
at java.base/java.security.cert.CertPathValidator.validate(CertPathValidator.java:309) ~[na:na]
at com.mysql.cj.protocol.ExportControlled$X509TrustManagerWrapper.checkServerTrusted(ExportControlled.java:402) ~[mysql-connector-java-8.0.29.jar:8.0.29]
如果客户端证书丢失,我们会得到一个不同的错误:
Caused by: java.sql.SQLException: Access denied for user 'test_user'@'172.20.0.1'
4.3.使用环境变量配置TLS
或者,我们可以将上述配置设置为环境变量,并将SSL 相关的配置作为JVM 参数。
让我们添加TLS 和Spring 相关的配置作为环境变量:
export TRUSTSTORE=./mysql-server/certs/truststore.jks
export TRUSTSTORE_PASSWORD=mypassword
export KEYSTORE=./mysql-server/certs/client-cert.jks
export KEYSTORE_PASSWORD=mypassword
export SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/test_db?sslMode=VERIFY_CA
export SPRING_DATASOURCE_USERNAME=test_user
export SPRING_DATASOURCE_PASSWORD=Password2022
然后,让我们使用上述SSL 配置运行应用程序:
$java -Djavax.net.ssl.keyStore=$KEYSTORE \
-Djavax.net.ssl.keyStorePassword=$KEYSTORE_PASSWORD \
-Djavax.net.ssl.trustStore=$TRUSTSTORE \
-Djavax.net.ssl.trustStorePassword=$TRUSTSTORE_PASSWORD \
-jar ./target/spring-boot-mysql-0.1.0.jar
5. 验证TLS 连接
现在让我们使用上述任何方法运行应用程序并验证TLS 连接。
可以使用MySQL 服务器常规日志或通过查询process
和sys
管理表来验证TLS 连接。
让我们使用默认路径/var/lib/mysql/
中的日志文件来验证连接:
$ cat /var/lib/mysql/7f44397082d7.log
2022-09-17T13:58:25.887830Z 19 Connect [email protected] on test_db using SSL/TLS
或者,让我们验证test_user
使用的连接:
mysql> SELECT process.thd_id,user,db,ssl_version,ssl_cipher FROM sys.processlist process, sys.session_ssl_status session
where process.user='[email protected]'and process.thd_id=session.thread_id;
六,结论
在本文中,我们了解了与MySQL 的TLS 连接如何使网络上的数据安全。此外,我们还了解了如何在Spring Boot 应用程序中配置MySQL 服务器上的TLS 连接。
0 评论