安全一直是不可不重视的问题。目前MySQL这方面应大方向上技术手段都具备。如:网络链接,权限控制,key秘钥认证,数据加密脱敏 等方式。综合考虑,虽然很多环境无法所有这些安全策略全部应用上,但在可控范围内尽量做到一定的防范实施。
其中SSL是属于加密连接方式,提供以下安全服务:
- 客户机和服务器之间的,通过使用公开密钥和对称密钥技术以达到信息保密。
- 信息完整性,确保SSL业务全部达到目的。应确保服务器和客户机之间的信息内容免受破坏。
- 双向认证,客户机和服务器相互识别的过程。它们的识别号用公开密钥编码,并在SSL握手时交换各自的识别号。
- 安全性服务对终端用户来讲做到尽可能透明。
SSL介绍
SSL定义:
SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。
SSL证书:
SSL安全证书是由权威认证机构颁发的,是CA机构将公钥和相关信息写入一个文件,CA机构用私钥对公钥和相关信息进行签名后,将签名信息也写入这个文件后生成的一个文件。 简单理解就是客户申请后,签发机构给一个唯一的文件,然后客户安装到服务器上进行使用,这个唯一的文件就是SSL证书。
备注:
X.509:是一种证书格式,对X.509证书来说,认证者总是CA或由CA指定的人,一份X.509证书是一些标准字段的集合,这些字段包含有关用户或设备及其相应公钥的信息。
OpenSSL 相当于SSL的一个实现,如果把SSL规范看成接口,那么OpenSSL则认为是接口的实现。
MySQL里SSL使用方式
MySQL中SSL功能支持客户端到服务器端的认证。主要用来提供对用户和服务器的认证;对传送的数据进行加密和隐藏;确保数据在传送中不被改变,即数据的完整性。
TLS(Transport Layer Security)是更为安全的升级版SSL。SSL表示安全套接字层,而TLS表示传输层安全。
实际上,目前MySQL使用的就是TLS协议,而不是单纯的SSL协议(如:status的ssl信息TLS_AES_256_GCM_SHA384)
mysql> status
--------------
mysql Ver 8.0.31 for Linux on x86_64 (MySQL Community Server - GPL)
Connection id: 22
Current database:
Current user: ssluser@iZuf6178v14ipc59jbbpfnZ
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
#表示用户采用SSL连接到mysql服务器如上,如果不是显示"Not in use"
。。。
--------------
MySQL中SSL和RSA文件具有以下特征:
- SSL和RSA密钥的大小为2048位。
- SSL CA证书是自签名的。
- 使用sha256WithRSAEncryption签名算法,使用CA证书和密钥对SSL服务器和客户端证书进行签名。
- SSL证书使用以下通用名称(CN)值以及相应的证书类型(CA,服务器,客户端):
ca.pem: MySQL_Server_suffix_Auto_Generated_CA_Certificate
server-cert.pm: MySQL_Server_suffix_Auto_Generated_Server_Certificate
client-cert.pm: MySQL_Server_suffix_Auto_Generated_Client_Certificate
后缀的值基于MySQL的版本号。由mysql_ssl_rsa_setup执行生成的文件,也可以使用suffix选项显式指定后缀。对于服务器生成的文件,如果生成的CN值超过64个字符,则省略名称的_suffix部分。
- SSL文件的“国家”©、“州或省”(ST)、“组织”(O)、“组织单位名称”(OU)和“电子邮件地址”为空。
- 由服务器或mysql_ssl_rsa_setup创建的SSL文件自生成之日起10年内有效。
- RSA文件不过期。
- 对于每个证书/密钥对,SSL文件具有不同的序列号(1用于CA, 2用于服务器,3用于客户机)。
- 由服务器自动创建的文件由运行服务器的帐户拥有。使用mysql_ssl_rsa_setup创建的文件由调用该程序的用户拥有。可以通过chown调用的系统上进行更改,如果程序是由root调用的,并且给出了——uid选项来指定应该拥有文件的用户。
- 在Unix和类系统上,证书文件的文件访问模式是644(即世界可读),密钥文件的文件访问模式是600(即仅由运行服务器的帐户访问)。
ssl文件可以通过Openssl命令手动生成,但mysql里已经提供mysql_ssl_rsa_setup自动创建:
#执行创建证书命令前先停止msyql实例
shell> mysql_ssl_rsa_setup --datadir=/opt/data8.0 --verbose
2022-12-08 10:15:22 [NOTE] Destination directory: /opt/data8.0
2022-12-08 10:15:22 [NOTE] Executing : openssl version
OpenSSL 1.1.1k FIPS 25 Mar 2021
2022-12-08 10:15:22 [NOTE] Executing : openssl req -newkey rsa:2048 -days 3650 -nodes -keyout ca-key.pem -subj /CN=MySQL_Server_8.0.31_Auto_Generated_CA_Certificate -out ca-req.pem && openssl rsa -in ca-key.pem -out ca-key.pem
Ignoring -days; not generating a certificate
Generating a RSA private key
.............................................................................................+++++
................................................................................+++++
writing new private key to 'ca-key.pem'
-----
writing RSA key
2022-12-08 10:15:22 [NOTE] Executing : openssl x509 -sha256 -days 3650 -extfile cav3.ext -set_serial 1 -req -in ca-req.pem -signkey ca-key.pem -out ca.pem
Signature ok
subject=CN = MySQL_Server_8.0.31_Auto_Generated_CA_Certificate
Getting Private key
。。。
..................................+++++
...................................................+++++
writing new private key to 'server-key.pem'
-----
writing RSA key
2022-12-08 10:15:22 [NOTE] Executing : openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 2 -req -in server-req.pem -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
Signature ok
subject=CN = MySQL_Server_8.0.31_Auto_Generated_Server_Certificate
Getting CA Private Key
。。。
..+++++
..............................................................................................................+++++
writing new private key to 'client-key.pem'
-----
writing RSA key
2022-12-08 10:15:23 [NOTE] Executing : openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 3 -req -in client-req.pem -CA ca.pem -CAkey ca-key.pem -out client-cert.pem
Signature ok
subject=CN = MySQL_Server_8.0.31_Auto_Generated_Client_Certificate
Getting CA Private Key
2022-12-08 10:15:23 [NOTE] Executing : openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
server-cert.pem: OK
client-cert.pem: OK
2022-12-08 10:15:23 [NOTE] Executing : openssl genrsa -out private_key.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.............................+++++
.+++++
e is 65537 (0x010001)
2022-12-08 10:15:23 [NOTE] Executing : openssl rsa -in private_key.pem -pubout -out public_key.pem
writing RSA key
2022-12-08 10:15:23 [NOTE] Success!
生成的8个pem文件:
shell> ll data/mysql/*.pem
-rw------- 1 mysql mysql 1676 Dec 6 11:11 ca-key.pem
-rw-r--r-- 1 mysql mysql 1112 Dec 6 11:11 ca.pem
-rw-r--r-- 1 mysql mysql 1112 Dec 6 11:11 client-cert.pem
-rw------- 1 mysql mysql 1676 Dec 6 11:11 client-key.pem
-rw-r--r-- 1 mysql mysql 1680 Sep 19 23:35 private_key.pem
-rw-r--r-- 1 mysql mysql 452 Sep 19 23:35 public_key.pem
-rw-r--r-- 1 mysql mysql 1112 Dec 6 11:11 server-cert.pem
-rw------- 1 mysql mysql 1680 Dec 6 11:11 server-key.pem
文件说明ca.pemCA证书ca-key.pemCA证书密钥client-cert.pem客户端使用的证书client-key.pem客户端使用的密钥server-cert.pem服务端使用的证书server-key.pem服务端使用的密钥private_key.pem私钥public_key.pem公钥
- 查看SSL证书的内容: 检查它的有效日期范围,调用openssl命令:
shell> openssl x509 -text -in client-cert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = MySQL_Server_8.0.31_Auto_Generated_CA_Certificate
Validity
Not Before: Dec 6 03:11:19 2022 GMT
Not After : Dec 3 03:11:19 2032 GMT
Subject: CN = MySQL_Server_8.0.31_Auto_Generated_Client_Certificate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c9:ea:ec:b1:9a:88:99:33:2f:e9:17:cc:d2:4a:
↓
91:9d:b4:ee:66:19:7a:b1:fb:ca:ae:4a:d5:41:c6:
a4:eb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
Signature Algorithm: sha256WithRSAEncryption
6f:09:b9:7d:d7:83:6c:72:3f:c4:8a:17:2a:f6:c7:0d:4a:22:
↓
a5:2f:1a:e4
-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIBAzANBgkqhkiG9w0BAQsFADA8MTowOAYDVQQDDDFNeVNR
↓
eTixiNaMvkBXxDUky4xWZ00XU76ei6pWE8h1wP6OfUpw8NFZ7Wt4/dvRD2AtFxDH
PB0i6ppH/KUvGuQ=
-----END CERTIFICATE-----
- 通过SQL语句检查SSL证书过期时间:
mysql> SHOW STATUS LIKE 'Ssl_server_not%';
+-----------------------+--------------------------+
| Variable_name | Value |
+-----------------------+--------------------------+
| Ssl_server_not_after | Dec 3 03:11:19 2032 GMT |
| Ssl_server_not_before | Dec 6 03:11:19 2022 GMT |
+-----------------------+--------------------------+
2 rows in set (0.00 sec)
- 配置文件设置:
[mysqld]
ssl_ca=ca.pem
ssl_cert=server-cert.pem
ssl_key=server-key.pem
require_secure_transport=ON
备注:require_secure_transport参数
客户端与服务器的连接是否需要使用某种形式的安全传输。启用此变量后,服务器仅允许使用TLS/SSL加密的TCP/IP连接,或使用套接字文件(在Unix上)或共享内存(在Windows上)的连接。
此功能补充了每个帐户的SSL要求,这些要求优先。例如,如果使用REQUIRE SSL定义帐户,下面有介绍账号生成规则。
- 密钥文件的访问权限: 私钥只能由服务器读取,而公钥可以自由分发给客户端用户。
chmod 400 private_key.pem
chmod 444 public_key.pem
- Client重用SSL: 从MySQL 8.0.29开始,客户端程序可以选择恢复前的SSL的session,前提是服务器在其运行时缓存中有该会话。SSL重用当然是为了减少重新创建链接开销。
- 服务器必须将其会话缓存保存在内存中。
- 服务器端会话缓存超时必须未过期。
- 每个客户端都必须维护活动会话的缓存并保持其安全
#ssl_session_cache开启和重用有效时间
mysql> SHOW VARIABLES LIKE '%ssl_session%';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| ssl_session_cache_mode | ON |
| ssl_session_cache_timeout | 300 |
+---------------------------+-------+
2 rows in set (0.01 sec)
#ssl_session状态
mysql> SHOW STATUS LIKE 'Ssl_session%';
+-----------------------------+--------+
| Variable_name | Value |
+-----------------------------+--------+
| Ssl_session_cache_hits | 0 |
| Ssl_session_cache_misses | 0 |
| Ssl_session_cache_mode | SERVER |
| Ssl_session_cache_overflows | 0 |
| Ssl_session_cache_size | 128 |
| Ssl_session_cache_timeout | 300 |
| Ssl_session_cache_timeouts | 0 |
| Ssl_sessions_reused | 0 |
+-----------------------------+--------+
8 rows in set (0.00 sec)
MySQL客户端程都能够重用先前的会话,用于与同一服务器建立新的加密连接,前提是在原始连接仍处于活动状态时存储会话数据。会话数据存储到一个文件中,在再次调用客户端时指定该文件。
#调用ssl_session_data_print命令指定可以安全地存储当前活动会话数据的文件的路径
mysql> ssl_session_data_print ~/private-dir/session.txt
#调用任何MySQL客户端来建立到同一服务器的新的加密连接。重用会话数据
shell> mysql -u admin -p --ssl-session-data=~/private-dir/session.txt
SSL如何使用
- 链接客户端工具: 如果不想使用ssl则增加–ssl=0选项或–ssl-mode=DISABLED
shell> mysql -uroot -proot --ssl=0或
shell> mysql -uroot -proot --ssl-mode=DISABLED
#参数ssl指定
shell> mysql -ussluser -p -P3306 -h192.168.1.1
--ssl-ca=/opt/ca.pem
--ssl-key=/opt/client-key.pem
--ssl-cert=/opt/client-cert.pem
- 用户使用强制使用SSL: ssl用户有如下参数tls_option: { SSL : 帐户下分发的语句进行加密连接。 | X509 : 客户端必须发送一个有效的X509证书 | CIPHER ‘cipher’ : 指定加密算法 | ISSUER ‘issuer’ :客户端的证书是否是服务器所配置的CA颁发 | SUBJECT ‘subject’ : 认证证书的subject | NONE : 不进行认证 }
#新建用户 ssl mysql> GRANT SELECT ON *.* to 'dba'@'%' IDENTIFIED BY 'xxx' REQUIRE SSL; #修改用户 mysql> ALTER USER 'dba'@'%' REQUIRE SSL; mysql> FLUSH PRIVILEGES;
- 驱动程序: 如:jdbc设置ssl
driverClassName=com.mysql.cj.jdbc.Driver
"jdbc:mysql://192.168.244.1:3306/sample?useUnicode=true&useSSL=true&
trustCertificateKeyStorePassword=123456&serverTimezone=Asia/Shanghai&
trustCertificateKeyStoreUrl=http://localhost:8080/mysql.ks
如果直接配置了连接属性verifyServerCertificate=true&useSSL=true&requireSSL=true,启动项目会报错,缺少证书
trustCertificateKeyStorePassword=设置的密钥,
trustCertificateKeyStoreUrl=当前服务器可访问到证书的地址,
useSSL=true,verifyServerCertificate=true代表需要客户端密钥库和信任库
备注:可以使用jdk自带的keytool工具导入mysql客户端证书到密钥仓库,并生成秘钥仓库文件。
- Navicat客户端配置ssl: 需要CA.pem,client-key.pem,client-ceart.pem文件
- caching_sha2_password: MySQL Server 使用 caching_sha2_password(MySQL8.0默认的认证插件)、sha256_password 认证插件,则还必须指定 AllowPublicKeyRetrieval=True,因为 caching_sha2_password 插件要求交换密码时必须使用 RSA 公钥加密
shell> mysql -udbadmin -p123456 -h192.168.1.1 -P3380 \
--server-public-key-path=/opt/data/public_key.pem
性能测试
开启SSL后,必定带来的一定的性能影响。从SSL实现来看,建立连接时需要进行握手、加密、解密等操作,之后数据传输也有包含加密解密过程。所以耗时大的一般在建立连接阶段。
sysbench对于ssl-key参数没开放,简单采用mysqlslap进行测试
shell> mysqlslap -ussluser -p123456 -P3380 -h192.168.244.129 \
--ssl-ca=/opt/ca.pem \
--ssl-key=/opt/client-key.pem \
--ssl-cert=/opt/client-cert.pem \
--create-schema=test -a -c 38 -i 500
数据库TPS/QPS平均降低了10~20%。还是比较影响性能的。对于使用短链接的应用程序可能产生更大的性能损耗,比如采用PHP开发。不过如果使用连接池 或 长连接可能会好许多。
总结
SSL安全能预防诸多一定程度的攻击。在传输过程中,如被黑客截获加密数据,在没有私有解密密钥的情况下无法读取或使用它。 可以说SSL使得更加安全。对于MySQL国内环境中,SSL使用场景还是比较少,因为数据库和应用之间内部网络进行交互,除此之外 外围防火墙也会起到很好的隔离作用。
- MySQL5.7高版本 MySQL8.0默认是开启SSL连接,如果强制用户使用SSL,那么应用配置也需要明确指定SSL相关参数,否则程序会报错;
- SSL下tcpdump类似抓包工具,是无法抓到 或 抓到了也无法看到信息;
- SSL下复制集(主从复制,MGR集群)都需要设置SSL配置协议;
- 虽然SSL方式使得安全性提高,但是相对地使得TPS/QPS也降低10%~20%。所以要谨慎选择;
- 对于非常敏感核心的数据,性能损失,换来的更高的数据安全性;
- 对于采用短链接、要求高性能的应用,或 不产生核心敏感数据的应用,性能和可用性才是首要,建议不要采用SSL方式;
版权归原作者 Kevin崔 所有, 如有侵权,请联系我们删除。