通过 MySQL 客户端和服务器之间的未加密连接,有权访问网络的人可以监视您的所有流量并检查客户端和服务器之间发送或接收的数据,因此 MySQL 支持使用 TLS 协议在客户端和服务器之间进行数据加密、数据完整性检查、通信两端身份验证
MySQL TLS 版本支持情况:
- MySQL 8.0.15 and below :TLS 1.0 、TLS 1.1 、TLS 1.2
- MySQL 8.0.28 and above :TLS 1.2 、TLS 1.3
- 特别要注意的是,要使用 TLSv1.3,MySQL 服务器和客户端应用程序都必须使用 OpenSSL 1.1.1 或更高版本进行编译。 MySQL 服务器在启动时检查 OpenSSL 的版本,如果低于 1.1.1,则从与 TLS 版本相关的服务器系统变量(tls_version 、admin_tls_version 、group_replication_recovery_tls_version)的默认值中删除 TLSv1.3
- 查看 MySQL Server 端当前使用的 tls 版本:
SHOW GLOBAL VARIABLES LIKE 'tls_version'
;
创建 TLS 证书
1、创建根证书
# 创建 CA 私钥 ca-key.pem
openssl genrsa -out ca-key.pem 2048
# 创建 CA 证书 ca-cert.pem
openssl req -sha256 -new -x509 -days 36500 -key ca-key.pem -out ca-cert.pem -subj "/C=CN/ST=BJ/L=BeiJing/O=TechQ/OU=JiaWen/CN=JiaWen/emailAddress=admin@163.com"
2、创建 MySQL Server 端证书(用于 mysql client 端对 server 端进行验证)
# 创建 mysql server 端私钥
openssl genrsa -out server-key.pem 2048
# CN=192.168.31.89 需设置为 mysql server 主机名或 IP 地址,可设置多个 CN 配置
openssl req -new -sha256 -key server-key.pem -out server-csr.pem -subj "/C=CN/ST=BJ/L=BeiJing/O=TechQ/OU=JiaWen/CN=192.168.31.89/CN=localhost/emailAddress=admin@163.com"
# 使用 ca 签发证书
openssl ca -in server-csr.pem -md sha256 -days 36500 -cert ca-cert.pem -keyfile ca-key.pem -extensions v3_req -out server-cert.pem
3、创建 MySQL Client 端证书(用于 mysql server 端对 client 端进行验证)
# 创建 mysql client 端私钥
openssl genrsa -out client-key.pem 2048
# CN=192.168.31.90 可为任意值吗 ??
openssl req -new -sha256 -key client-key.pem -out client-csr.pem -subj "/C=CN/ST=BJ/L=BeiJing/O=TechQ/OU=JiaWen/CN=192.168.31.90/emailAddress=admin@163.com"
# 使用 ca 签发证书
openssl ca -in client-csr.pem -md sha256 -days 36500 -cert ca-cert.pem -keyfile ca-key.pem -extensions v3_req -out client-cert.pem
MySQL Server 端配置
1、启用加密连接,并配置根证书及用于 MySQL Server 端的证书及私钥
[mysqld]
# 将 mysql server 配置为要求客户端使用 SSL/TLS 协议进行加密连接
require_secure_transport=ON
tls_version=TLSv1.2
# 证书配置
ssl_ca=ca-cert.pem
ssl_cert=server-cert.pem
ssl_key=server-key.pem
证书及密码文件默认存放于 MySQL 数据目录 /var/lib/mysql/
2、将各个 MySQL 帐户配置为只能通过加密连接使用
CREATE USER 'user01'@'%' REQUIRE X509;
ALTER USER 'user02'@'%' REQUIRE SSL;
CREATE USER 'user01'@'%' IDENTIFIED BY 'user123' REQUIRE SSL;
??
服务器端哪个配置项,体现了对客户端证书进行验证 ??
MySQL Client 端配置
当 mysql server 支持加密连接时,命令mysql
默认会尽可能与 server 端建立加密连接
1、mysql 连接示例
# 1、仅 Server 端被单向验证
mysql -h 192.168.31.89 -P 3306 -u root -p --ssl-mode=VERIFY_IDENTITY --ssl-ca=ca-cert.pem
# 2、Server 端及 Client 端双向验证,彼此验证对方
mysql -h 192.168.31.89 -P 3306 -u root -p --ssl-mode=VERIFY_IDENTITY --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem
# 主要选项说明
--ssl-ca # 指定 client 端用于验证 server 证书的根证书,PEM 格式 X509 证书
--ssl-cert # 指定 client 端证书,PEM 格式 X509 证书
--ssl-key # 指定 client 端私钥,PEM 格式 X509 私钥
--ssl-cipher # 设置 ssl 加密套件
--tls-ciphersuites # 适用于 TLS v1.3 的加密套件设置
2、默认情况下,如果 MySQL Server 支持 TLS,MySQL 客户端程序会尝试建立加密连接,可通过 --ssl-mode 选项进行进一步控制
,可选设置项: 推荐 VERIFY_IDENTITY
PREFERRED # 默认值,尽量使用加密连接,若失败则回退到非加密连接
DISABLED # 使用非加密连接
REQUIRED # 使用加密连接
VERIFY_CA # 使用加密连接,并检查 mysql server 端证书是否有效
VERIFY_IDENTITY # 使用加密连接,并检查 mysql server 端证书是否有效,与此同时验证 server 端证书的 hostname 是否与 client 实际连接时使用的 hostname 是否一致
为帮助防止复杂的中间人攻击,客户端验证服务器的身份非常重要,因此设置--ssl-mode = VERIFY_CA 或 VERIFY_IDENTITY
时,比默认设置更安全,有助于防止此类攻击
mysql server 端证书 hostname 配置对应 x509 扩展配置项:X509v3 Subject Alternative Name
,可通过命令openssl x509 -text -in server-cert.pem -noout
查看
#> Certificate:
#> Data:
#> Version: 3 (0x2)
#> Serial Number: 1 (0x1)
#> Signature Algorithm: sha256WithRSAEncryption
#> Issuer: C=CN, ST=BJ, L=BeiJing, O=TechQ, OU=JiaWen, CN=JiaWen/emailAddress=admin@163.com
#> Validity
#> Not Before: Oct 16 08:47:27 2023 GMT
#> Not After : Oct 13 08:47:27 2033 GMT
#> Subject: C=CN, ST=BJ, O=TechQ, OU=JiaWen, CN=192.168.31.89/emailAddress=admin@qq.com
#> Subject Public Key Info:
#> Public Key Algorithm: rsaEncryption
#> Public-Key: (2048 bit)
#> Modulus:
#> 00:e4:7f:fa:75:4a:15:b6:26:b0:b9:01:b4:13:59:
#> ...
#> 0f:8f:fa:41:02:9a:dc:87:33:4a:5a:02:bb:b3:03:
#> 43:17
#> Exponent: 65537 (0x10001)
#> X509v3 extensions:
#> X509v3 Basic Constraints:
#> CA:FALSE
#> X509v3 Key Usage:
#> Digital Signature, Non Repudiation, Key Encipherment
#> X509v3 Subject Alternative Name:
#> DNS:localhost, IP Address:192.168.31.89
#> Signature Algorithm: sha256WithRSAEncryption
#> 20:30:49:41:2d:18:b1:53:93:51:65:9c:45:15:2c:38:1d:f6:
#> ...
#> fd:fe:6f:f9:b0:25:4f:b6:d5:e4:41:66:35:2a:19:74:5a:1f:
#> be:04:98:8e
当使用选项 VERIFY_IDENTITY 时,mysql -h 指定的主机名必须为 localhost 或 192.168.31.89 才能建立加密连接。例如,通过如下命令建立加密连接时将失败:
mysql -h 127.0.0.1 -P 3306 -u root -proot --ssl-mode=VERIFY_CA --ssl-ca=ca-cert.pem
#> ERROR 2026 (HY000): SSL connection error: SSL_CTX_set_default_verify_paths failed
因此,当 MySQL Server 存在多个主机 IP 时,需将这些 IP 地址加入到 X509v3 证书扩展选项 Subject Alternative Name (SAN)
中
验证是否为 TLS 加密连接
1、查询当前 Client 到 MySQL Server 端是否为 TLS 加密连接
SELECT id, user, host, connection_type
FROM performance_schema.threads pst
INNER JOIN information_schema.processlist isp
ON pst.processlist_id = isp.id;
--> +----+-----------------+---------------------+-----------------+
--> | id | user | host | connection_type |
--> +----+-----------------+---------------------+-----------------+
--> | 5 | event_scheduler | localhost | NULL |
--> | 12 | root | localhost:36814 | SSL/TLS |
--> | 13 | root | 192.168.31.90:44112 | SSL/TLS |
--> +----+-----------------+---------------------+-----------------+
运行时动态配置 TLS 相关变量(可选)
在 MySQL 8.0.16 之前,只能在服务器启动时配置加密连接支持的 tls_xxx 和 ssl_xxx 系统变量。而从 MySQL 8.0.16 开始,tls_xxx 和 ssl_xxx 系统变量是动态的,可以在运行时设置,而不仅仅是在启动时设置;运行时动态设置,可以避免重新启动运行时间过长以致其 SSL 证书已过期
的 MySQL 服务器。具体相关配置项可通过如下命令查看:
MySQL localhost:33060+ ssl SQL > show variables like '%tls%';
#> +------------------------+---------+
#> | Variable_name | Value |
#> +------------------------+---------+
#> | admin_tls_ciphersuites | |
#> | admin_tls_version | TLSv1.2 |
#> | tls_ciphersuites | |
#> | tls_version | TLSv1.2 |
#> +------------------------+---------+
MySQL localhost:33060+ ssl SQL > show variables like '%ssl%';
#> +-------------------------------------+-----------------+
#> | Variable_name | Value |
#> +-------------------------------------+-----------------+
#> | have_openssl | YES |
#> | have_ssl | YES |
# 适用于 mysqladmin 的加密连接选项
#> | admin_ssl_ca | |
#> | admin_ssl_capath | |
#> | admin_ssl_cert | |
#> | admin_ssl_cipher | |
#> | admin_ssl_crl | |
#> | admin_ssl_crlpath | |
#> | admin_ssl_key | |
# 适用于 mysqlsh 的加密连接选项
#> | mysqlx_ssl_ca | |
#> | mysqlx_ssl_capath | |
#> | mysqlx_ssl_cert | |
#> | mysqlx_ssl_cipher | |
#> | mysqlx_ssl_crl | |
#> | mysqlx_ssl_crlpath | |
#> | mysqlx_ssl_key | |
# 适用于 mysql 及 应用程序的加密连接选项
#> | ssl_ca | ca.pem |
#> | ssl_capath | |
#> | ssl_cert | server-cert.pem |
#> | ssl_cipher | |
#> | ssl_crl | |
#> | ssl_crlpath | |
#> | ssl_fips_mode | OFF |
#> | ssl_key | server-key.pem |
#> | ssl_session_cache_mode | ON |
#> | ssl_session_cache_timeout | 300 |
#> +-------------------------------------+-----------------+
更改 openssl 版本 (可选)
默认情况下,MySQL 实例在运行时链接到系统上已安装的 OpenSSL 库,以支持加密连接和其它1与加密相关的操作,可使用状态变量 Tls_library_version (从 MySQL 8.0.30 开始提供)检查运行时正在使用的 OpenSSL 库版本
如果您使用一个版本的 OpenSSL 编译 MySQL,并且希望更改为不同的 OpenSSL 版本而不重新编译
,则可以通过编辑动态库加载器路径(Unix 系统上的 LD_LIBRARY_PATH )来实现。其具体实现思路如下:
删除 OpenSSL 编译版本的路径,然后添加替换版本的路径,并将其放置在路径上任何其他 OpenSSL 库之前,当 MySQL 启动时,在路径上找不到 WITH_SSL 指定的 OpenSSL 版本时,它会使用 LD_LIBRARY_PATH 路径上指定的第一个版本 !