1
MySQL中为了保证网络通信过程中数据的安全性,提供了相应的安全机制,本文主要对SSL/TLS机制简单介绍,其他安全机制会在后续文章中介绍。
以MySQL5.7为例,首先介绍MySQL中启动SSL/TLS的方法及相关配置,并对加密与非加密信道传输简单的对比,较直观的理解SSL/TLS的作用。随后会简单介绍SSL/TLS的基本思想,更好的理解各个PEM文件的作用。最后会介绍SSL/TLS在数据库中间件中实现的好处及MySQL源码中SSL/TLS相关的函数。
1.1 SSL/TLS加密信道的主要好处
数据保密性,防止窃听等
数据完整性,防止数据被篡改等
数据真实性和可追溯性,防止中间人攻击、抵赖等
1.2 SSL/TLS在MySQL中的常见应用
在MySQL中,SSL/TLS主要被用于以下几个方面:
客户端连接MySQL
主从复制
远程提取binlog(不在本文讨论范围)
1.3 SSL与TLS区别
SSL(Secure Socket Layer)是1994年由网景(Netscape)公司设计的一种安全的网络传输协议,并用于该公司的Web浏览器中,后多家Web浏览器相继采用该协议,成为了事实上的行业标准。SSL在1995年发布了3.0版本,但在2014年,SSL3.0被发现存在可能导致POODLE的安全漏洞,已不再安全。
TLS(Transport Layer Security)是IETF在SSL3.0基础上设计的协议,在1999年作为RFC2246发布的TLS1.0实际上相当于SSL3.1。后续的TLS版本陆续增加了更多防范攻击的策略,更加的安全。
本文将SSL于TLS作为一个整体对待。
2
2.1 基本配置(以Percona5.7.21为例)
安装Percona-server-57
sudo yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm
sudo yum install Percona-Server-server-57
sudo service mysql start
查看数据目录中各种SSL/TLS相关PEM格式文件
MySQL启动之后,会自动在数据目录创建SSL/TLS使用的PEM文件
sudo ls var/lib/mysql | grep -i pem
ca-key.pem
ca.pem
client-cert.pem
client-key.pem
server-cert.pem
server-key.pem
public_key.pem
private_key.pem
查看SSL/TLS相关配置
mysql> SHOW GLOBAL VARIABLES LIKE ‘%ssl%’;
+—————–+——————-+
| Variable_name | Value |
+—————–+——————-+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | ca.pem |
| ssl_capath | |
| ssl_cert | server-cert.pem|
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | server-key.pem|
+—————–+——————-+
9 rows in set (0.00 sec)
由于官方发布的RPM包编译时开启了SSL/TLS支持,因此在使用RPM安装MySQL时,会默认支持SSL/TLS协议并且自动生成相关的文件,因此上述显示的全局变量have_openssl的值为YES。注意,变量have_openssl是变量have_ssl的别名,have_ssl值为YES,表示mysqld支持SSL连接;值为NO,表示mysqld不支持SSL连接;值为DISABLE,表示mysqld编译时开启了SSL支持,但是没有正确配置ssl相关选项。
启动后,SSL/TLS所需要的PEM文件会默认生成在数据目录,当然也可以在配置文件中指定PEM文件,方法如下:
[mysqld]
ssl-ca=ca.pem
ssl-cert=server-cert.pem
ssl-key=server-key.pem
2.2 客户端连接MySQL
MySQL客户端连接时,默认开启SSL。可以通过使用 --ssl-mode=DISABLED
或 --skip-ssl
来禁用SSL/TLS协议,例如:
mysql -u -p xx -h xx -P xx
--ssl-mode=DISABLED
可以通过下面命令查看当前连接是否使用了SSL/TLS协议:
mysql>status
Connection id: 13900
Current database:
Current user: root@localhost
SSL: Cipher in use is DHE-RSA-AES128-GCM-SHA256
上述status命令也可以简写成\s。如果使用了SSL/TLS协议的连接,会在SSL这一行显示使用的算法信息,如果当前连接没有使用SSL/TLS,该行会显示为:“Not in use”。
除了上述方法查看当前连接是否使用了SSL/TLS之外,还可以通过查看session级变量Ssl-cipher
,查看当前连接的加密算法,如果该值为空,则说明没有使用加密连接。方法如下(各类算法含义不再赘述):
mysql>SHOW SESSION STATUS LIKE ‘Ssl_cipher’
+————————-+——————————————+
| Variable_name | Value |
+————————-+——————————————+
| Ssl_cipher | DHE-RSA-AES128-GCM-SHA256 |
+————————-+——————————————+
在不显式的指定参数--ssl-mode
时,即默认情况下客户端会优先尝试建立SSL/TLS连接,如果SSL/TLS连接无法建立,则会尝试建立非SSL/TLS连接,其行为与指定参数--ssl-mode=PREFERRED
行为一致。
参数--ssl-mode
可以指定不同的参数值,各个参数值的含义如下所示:
ssl-mode取值 | 含义 |
DISABLED | 与参数skip-ssl一样,不使用SSL/TLS建立加密连接 |
PREFERRED | 优先尝试使用SSL/TLS建立加密连接,如果无法建立则尝试建立非SSL/TLS连接 |
REQUIRED | 只会尝试使用SSL/TLS建立加密连接 |
VERIFY_CA | 与REQUIRED行为一样,与此同时会验证server端的证书是否有效 |
VERIFY_IDENTITY | 与VERIFY_CA行为一样,与此同时验证server端证书的host是否与实际连接的hostname一致 |
客户端在指定了--ssl-mode=VERIFY_CA
时,需要使用--ssl-ca
来指定CA证书;在指定了--ssl-mode=VERIFY_IDENTITY
后,除了需要指定CA证书外还需要使用--ssl-key
指定客户端的私钥,使用--ssl-cert
指定客户端的证书。
2.2 主从复制
主从复制使用SSL/TLS连接的配置方法与client/server使用SSL/TLS连接的配置方法类似。
在master节点,可以在配置文件中配置以下内容,或是数据目录有对应的文件:
[mysqld]
ssl-ca=ca.pem
ssl-cert=server-cert.pem
ssl-key=server-key.pem
在slave节点上,类似的可以在配置文件中如下配置:
[client]
ssl-ca=ca.pem
ssl-cert=client-cert.pem
ssl-key=client-key.pem
使用CHANGE MASTER TO
语句来指定master 信息时,只需要添加MASTER_SSL选项即可开启SSL/TLS协议进行Binlog同步:
mysql> CHANGE MASTER TO
-> MASTER_HOST=’master_hostname’,
-> MASTER_USER=’repl’,
-> MASTER_PASSWORD=’password’,
-> MASTER_SSL=1;
当设置MASTER_SSL=1
时,其行为与--ssl-mode=PREFERRED
的行为一致,即优先尝试SSL/TLS连接,若无法建立则再尝试非SSL/TLS连接。同理,如果设置MASTER_SSL=0
时,其行为与--ssl-mode=DISABLED
一致。
同样的,如果没有在配置文件中指明所使用的PEM文件,可以在CHANGE MASTER
时进行指定,语法如下:
-> MASTER_SSL_CA = ‘ca_file_name’,
-> MASTER_SSL_CAPATH = ‘ca_directory_name’,
-> MASTER_SSL_CERT = ‘cert_file_name’,
-> MASTER_SSL_KEY = ‘key_file_name’,
同理,如果在CHANGE MASTER
语句中指定了MASTER_SSL_CA或是MASTER_SSL_CAPATH,或是在配置文件中配置了对应参数,则其行为与client端配置了--ssl-mode=VERIFY_CA
行为一致。如果希望验证hostname的有效性,可以添加如下参数,其行为则与client端配置了--ssl-mode=VERIFY_IDENTITY
一致:
-> MASTER_SSL_VERIFY_SERVER_CERT=1,
如果希望确保从库的复制是使用SSL/TLS建立的连接,可以在创建账号时,指定REQUIRE SSL选项。
mysql> CREATE USER ‘repl’@’%.example.com’ IDENTIFIED BY ‘password’
-> REQUIRE SSL;mysql> GRANT REPLICATION SLAVE ON .
-> TO ‘repl’@’%.example.com’;
如果复制账号已经存在,可以通过以下语句添加REQUIRE SSL选项:
mysql> ALTER USER ‘repl’@’%.example.com’ REQUIRE SSL;
其他参数和详细用法,可以参考官方文档,这里就不再赘述了。
2.3 手动构建CA
由于发布版本的MySQL在编译时开启了SSL/TLS,因此在安装包安装成功并启动MySQL之后,会自动创建SSL/TLS相关的PEM格式文件。具体细节可以参考MySQL官方文档相关章节。本章节主要介绍如何使用openssl自建CA系统。
下面的命令会生成CA秘钥和证书、server端的秘钥和证书,以及client端的秘钥和证书。在生成过程中,需要命令行输入一些参数,在测试时候,可以直接输入空,即按回车键跳过;但是在生产环境中,需要输入对应的正确信息。
# Create CA certificate
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem# Create server certificate, remove passphrase, and sign it
# server-cert.pem = public key, server-key.pem = private key
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem# Create client certificate, remove passphrase, and sign it
# client-cert.pem = public key, client-key.pem = private key
openssl req -newkey rsa:2048 -days 3600 -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
生成上述文件后,可以对其进行验证:
openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
也可以查看各个证书中的CN等信息:
openssl x509 -text -in ca.pem
openssl x509 -text -in server-cert.pem
openssl x509 -text -in client-cert.pem
为了更加直观的比较禁用与开启SSL/TLS协议后网络链路上传输的数据的变化,对TCP层进行抓包。下面是执行同一语句,在禁用和开启SSL/TLS协议情况下的抓包情况:
(client:172.17.0.4 server:172.17.0.3 SQL:select * from ght.test_ssl)
下面是开启SSL/TLS后的抓包结果:
#TCP Hex Data
From: 172.17.0.4:47428
To: 172.17.0.3:3306
Payload (56 bytes):
00000 17 03 03 00 33 70 9a 50 4d 47 1d eb e6 67 9c be ….3p.PMG…g..
00016 0d 9d 7b e2 47 c0 a6 80 63 0f 25 5b c4 14 c4 9e ..{.G…c.%[….
00032 9a 78 d0 04 ca 1c 45 e5 9f 25 ec 42 9f 99 67 1b .x….E..%.B..g.
00048 18 36 1e e7 32 a3 a3 a0 .6..2…# TCP Hex Data
From: 172.17.0.3:3306
To: 172.17.0.4:47428
Payload (98 bytes):
00000 17 03 03 00 5d 18 ec e8 34 d2 a3 e8 27 05 80 25 ….]…4…’..%
00016 6a 96 33 27 41 03 20 9a d9 97 bf 7b 0b 37 ba 89 j.3’A. ….{.7..
00032 e4 e0 54 2a 46 d4 1f fd 02 3b 12 16 12 a3 55 ce ..T*F….;….U.
00048 8a 09 35 d2 1a cf 2b 13 e3 72 c6 54 79 4a d1 c9 ..5…+..r.TyJ..
00064 b7 42 ac a0 45 f4 60 a3 5f 74 d5 df f2 9d 8c d9 .B..E.`._t……
00080 d4 80 e5 c3 c8 d5 d6 71 81 af e3 53 94 f3 76 fa …….q…S..v.
00096 39 4e 9N
下面是禁用SSL/TLS的抓包结果:
# TCP Hex Data
From: 172.17.0.4:46862
To: 172.17.0.3:3306
Payload (27 bytes):
00000 17 00 00 00 03 73 65 6c 65 63 74 20 2a 20 66 72 …..select * fr
00016 6f 6d 20 74 65 73 74 5f 73 73 6c om test_ssl#TCP Hex Data
From: 172.17.0.3:3306
To: 172.17.0.4:46862
Payload (69 bytes):
00000 01 00 00 01 01 2b 00 00 02 03 64 65 66 03 67 68 …..+….def.gh
00016 74 08 74 65 73 74 5f 73 73 6c 08 74 65 73 74 5f t.test_ssl.test_
00032 73 73 6c 01 61 01 61 0c 3f 00 0b 00 00 00 03 03 ssl.a.a.?…….
00048 50 00 00 00 02 00 00 03 01 31 07 00 00 04 fe 00 P……..1……
00064 00 02 00 00 00 …..
上述对比很直观的看到,没有使用SSL/TLS的数据传输,抓包结果中不仅可以获取发送的SQL语句,也可以获得结果集。网络传输的数据轻易的可以被监听、甚至修改等,可见在传输敏感数据的时候,开启SSL/TLS的重要性。
4
SSL/TLS协议的功能实现主要依赖三类基本算法:对称加密、公钥加密(非对称加密)和单向散列函数。其中利用公钥加密实现对称加密的秘钥协商和身份认证,利用对称加密用来对实际的数据进行加密,利用基于散列函数生成摘要验证数据完整性。
引入SSL/TLS的目的是在不安全的信道上进行安全的数据传输。由于MySQL对SSL/TLS的支持,需要配置一些PEM格式文件,各个文件的作用,通过分析SSL/TLS原理,便能更好的理解,下面进行简单的分析。
4.1 对称加密
明文在不安全的信道上传输,容易被窃取,无法保证数据的安全性。最容易想到的便是对明文进行加密,在不安全的信道上传输加密后的密文,接收到密文之后,通过相同的秘钥进行解密,最终获得原始的明文数据。这便是对称加密。
在对称加密系统中,发送端与接收端共享同一秘钥,即加密和解密的秘钥都一样。这就存在一个问题,即发送端和接收端如何对这一相同的秘钥安全的达成一致。
4.2 公钥加密
公钥加密与对称加密最大的不同是,其加密和解密使用不同的秘钥,即公钥和私钥。接收端可以将自己的公钥发布到网络,任何人都可以获得。当发送端有数据发往接受端时,发送端会使用接收端的公钥对待发送的数据进行加密,随后密文在信道传输,接收端获得密文后,会使用自己的私钥进行解密。由于只有接收端有私钥,而只有私钥才能解密,因此该数据传输是安全的。
但是,公钥加密的速度相对对称加密较慢,因此不适合加密大量待传输的数据。
4.3 混合加密
对称加密和公钥加密都各自有优缺点,对称加密加密速度较快,但是秘钥传递不安全;公钥加密秘钥传递安全,但是加密速度慢。因此可以将二者进行结合。
使用公钥加密对对称加密使用的秘钥进行加密,从而发送和接收方安全的获得对称加密的秘钥;之后,传输的数据便可以通过对称加密进行密文传输了。
虽然混合加密系统解决了防止网络监听等问题,但是却无法避免诸如中间人攻击等攻击手段。中间人攻击主要是利用了传输的双发无法确认对方身份而展开的伪造身份的攻击;与此同时,数据的完整性也得不到验证。因此需要一种机制,用来校验数据的完整性,并且能够确认发送、接受双方的身份。
4.4 单向散列与摘要
摘要是对原数据通过散列函数计算的哈希值,用于验证数据的完整性和唯一性,无论原始数据长度如何,计算得到的摘要长度是固定的,而摘要的计算方法是单向的算法。
之前介绍过,公钥加密系统中,加密数据时,使用公钥加密,私钥解密;而公钥加密系统还有个作用是进行签名,用来防止私钥所有者发布的内容被篡改,即使用私钥进行签名,使用公钥进行验证。
由于摘要的长度固定,且长度较小,因此可以对摘要使用公钥加密系统对摘要进行签名,用来进行身份的验证。
4.5 签名
假设发送端为B,接收端为A。B首先对原始数据计算摘要,对摘要使用B自己的私钥进行加密。然后将原始数据和摘要使用对称加密算法加密。由于可以通过公钥加密进行对称加密秘钥的交换,因此接收端A可以通过对称加密秘钥对B发送来的密文进行解密。保证了数据传输的安全性。
接收端A解密后,会得到原始数据和摘要。随后,A使用B的公钥可以验证发送端是否是B,从而验证了身份。
A使用同样的摘要算法对解密后的原始数据计算摘要,如果计算出来的摘要和通过网络接受到的摘要一样,则说明数据是完整的。
上述步骤中,极大依赖发送方的公钥,如何验证公钥的真实性,是接下来需要解决的问题。
4.6 CA
CA是证书授权中心,是区别于发送方和接收方的第三方机构,具有公信力和权威性。因此公钥的真实性的验证,需要依赖于CA。
CA拥有自己的私钥和公钥。在站点申请自己的证书的时候,CA会使用自己的私钥对证书进行加密,而CA的公钥可以发布到网络上,任何人都可以知道。
当获取某一个站点的公钥的时候,可以通过获取其签名的CA的公钥,来进行验证身份,验证成功,则说明该签名是该CA结构颁发的。
当然验证签名的完整性,同样可以通过证书中的摘要进行验证,类似4.4节所描述的,不再赘述。
与此同时,当获取A的证书后,也需要验证该证书的持有者是否就是A,验证过程,类似上面章节所描述的,也不再赘述。
当然,数字证书也有一些其他属性需要验证,例如:有效期以及是否被吊销等等。
4.7 MySQL中的CA相关文件
通过上述描述,应该已经很清楚MySQL为了支持SSL/TLS所构建的CA系统,以及所需要的这些PEM格式文件的作用了,下面再次进行简单阐述:
文件名称 | CA系统中的地位 | 作用 |
ca-key.pem | CA系统的私钥 | 用来对client/server的证书进行签名 |
ca.pem | CA 系统的公钥 | 用来验证client/server的证书是否是 CA颁发的 |
client/server-cert.pem | client/server的证书 | 用来验证消息发送方的身份的有效性 |
client/server-key.pem | client/server的私钥 | 用来对数据的摘要进行签名 |
5
5.1 SSL/TLS开销
SSL/TLS 解决了在不安全的网络下对数据进行安全的传输问题。但是,其带来的代价是增加连接建立时的握手次数和加密解密上的消耗。由于加密解密时间消耗和具体算法、硬件环境有关不方便衡量,而且使用专门的硬件可以降低加密、解密的耗时,下面只简单分析带来的网络耗时。
SSL/TLS对于网络来讲,主要是握手次数较多。curl工具提供了w参数用来测量TCP握手和SSL握手的具体耗时,以访问支付宝为例:
curl -w “TCP handshake: %{time_connect}, SSL handshake: %{time_appconnect}\n” -so dev/null https://www.alipay.com
执行10次,统计如下:
次数 | TCP耗时 | SSL耗时 |
1 | 0.088711 | 0.186048 |
2 | 0.094299 | 0.195923 |
3 | 0.158793 | 0.254043 |
4 | 0.031973 | 0.111132 |
5 | 0.056754 | 0.153739 |
6 | 0.032412 | 0.117574 |
7 | 0.161437 | 0.284077 |
8 | 0.031377 | 0.112822 |
9 | 0.041973 | 0.126571 |
10 | 0.09306 | 0.173615 |
AVG | 0.0790789 | 0.1715544 |
根据上述简单统计,SSL连接建立耗时大概是TCP连接建立耗时2倍左右,这些额外耗时主要是新建连接时SSL多出来的握手次数产生的。
SSL协议详细握手过程和抓包分析,网络上文章介绍的很清楚,就不再赘述。
5.2 中间件解决SSL连接建立耗时
上述分析不难看出,SSL/TLS的新建连接的过程耗时较为严重,而连接池技术则可以增加连接复用,降低新建连接的建立,可以有效地较少SSL/TLS连接建立的耗时。
MySQL数据库中间件通常都有自己的连接池,连接池中保存了中间件到数据库的有效连接,当使用连接时,会从连接池中申请连接,使用完毕,完好的连接再次回归连接池,从而达到连接复用的目的。在数据库中间件连接池的基础上,实现SSL/TLS协议,在保证数据库中间件到数据库网络链路上的安全性的同时,可以利用连接池的连接复用特性,减少SSL/TLS连接建立次数,兼顾性能。
ProxySQL中间件目前已经支持该功能,如下图所示。后续在网易乐得开源的Cetus中间件上也支持。
网易开源分布式MySQL中间件Cetus传送门:here
6
SSL/TLS相应的库中,提供了加密、解密、证书验证等丰富的API接口,这部分就不再赘述了。下面主要大致介绍下client/server使用SSL/TLS交互时涉及的主要函数,具体的函数实现细节,有兴趣的朋友可以直接阅读相关代码。
SSL/TLS交互的通用逻辑如下(有些步骤可以省略):
在MySQL中实现的流程类似。client端启动时候,会根据用户的参数,通过new_VioSSLFd()
来初始化一些结构和加载相关证书。之后,通过sslconnect()
调用ssl_do()
进入主流程,完成SSL的握手,之后会根据所协商的auth认证插件进行对应的认证过程。
server端SSL建立类似通过sslaccept()
调用ssl_do()
进入主流程,与client端不同的是,传入的回调函数是SSL_accept()
,而client端对应传入的回调函数为SSL_connect()
。
值得一提的是,当client建立连接时,指定参数--ssl-mode=VERIFY_IDENTITY
时的验证逻辑所在的函数为ssl_verify_server_cert()
,有兴趣可以阅读。
对具体细节感兴趣,可以阅读 ssl_do()
实现,不再展开了。
7 参考
6.4 Using Encrypted Connections
16.3.8 Setting Up Replication to Use Encrypted Connections
ProxySQL Improves MySQL SSL Connections
6.4.5 Building MySQL with Support for Encrypted Connections
SSL延迟有多大
推荐阅读




欢迎分享

网易乐得DBA组负责网易乐得电商、网易邮箱、网易技术部数据库日常运维,负责数据库私有云平台的开发和维护,负责数据库及数据库中间件的开发和测试等,分享最前沿实用数据库干货,关注网易乐得DBA,精修数据库功底。