MySQL 和 Spring Boot 應用程序中的 TLS 設置
一、概述
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 連接。
與往常一樣,可以在 GitHub 上找到示例代碼。