Skip to content

MySQL 传输加密

SSL/TLS 加密配置

1. 生成 SSL/TLS 证书

自签名证书生成

bash
# 创建证书存储目录
mkdir -p /etc/mysql/ssl
cd /etc/mysql/ssl

# 生成 CA 私钥
openssl genrsa 2048 > ca-key.pem

# 生成 CA 证书
openssl req -new -x509 -nodes -days 3650 -key ca-key.pem > ca.pem

# 生成服务器私钥
openssl genrsa 2048 > server-key.pem

# 生成服务器证书请求
openssl req -new -key server-key.pem -out server-req.pem

# 生成服务器证书
openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem

# 生成客户端私钥
openssl genrsa 2048 > client-key.pem

# 生成客户端证书请求
openssl req -new -key client-key.pem -out client-req.pem

# 生成客户端证书
openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 > client-cert.pem

# 转换私钥格式(可选)
openssl rsa -in server-key.pem -out server-key.pem
openssl rsa -in client-key.pem -out client-key.pem

# 设置权限
chmod 600 *-key.pem
chown mysql:mysql *

商业证书配置

  1. 从证书颁发机构(CA)获取商业证书
  2. 将证书文件上传到服务器
  3. 确保证书文件权限正确

2. MySQL 服务器 SSL 配置

配置文件设置

ini
[mysqld]
# SSL 配置
ssl-ca=/etc/mysql/ssl/ca.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem

# 强制客户端使用 SSL(可选)
# require_secure_transport=ON

# 禁用旧版加密协议
ssl-cipher=DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256

重启 MySQL 服务

bash
# 重启 MySQL 服务
systemctl restart mysqld

验证 SSL 配置

sql
-- 查看 SSL 配置状态
SHOW VARIABLES LIKE '%ssl%';

-- 验证 SSL 证书
SHOW STATUS LIKE 'Ssl_cipher';

客户端 SSL 连接配置

1. MySQL 命令行客户端

bash
# 使用 SSL 连接(不验证服务器证书)
mysql -u root -p --ssl

# 使用 SSL 连接并验证服务器证书
mysql -u root -p --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-cert=/etc/mysql/ssl/client-cert.pem --ssl-key=/etc/mysql/ssl/client-key.pem

# 强制使用 SSL
mysql -u root -p --ssl-mode=REQUIRED

2. 应用程序连接配置

Java 应用(JDBC)

java
// JDBC URL 配置
String url = "jdbc:mysql://localhost:3306/mydb?useSSL=true&requireSSL=true&verifyServerCertificate=true&serverTimezone=UTC";

// 加载证书
System.setProperty("javax.net.ssl.trustStore", "/path/to/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "password");

// 建立连接
Connection conn = DriverManager.getConnection(url, username, password);

Python 应用(MySQL Connector/Python)

python
import mysql.connector

# 配置 SSL 连接
cnx = mysql.connector.connect(
    host="localhost",
    user="root",
    password="password",
    database="mydb",
    ssl_ca="/etc/mysql/ssl/ca.pem",
    ssl_cert="/etc/mysql/ssl/client-cert.pem",
    ssl_key="/etc/mysql/ssl/client-key.pem",
    ssl_verify_cert=True
)

PHP 应用(PDO)

php
// PDO 配置
$dsn = "mysql:host=localhost;dbname=mydb;charset=utf8mb4";
$options = [
    PDO::MYSQL_ATTR_SSL_CA => "/etc/mysql/ssl/ca.pem",
    PDO::MYSQL_ATTR_SSL_CERT => "/etc/mysql/ssl/client-cert.pem",
    PDO::MYSQL_ATTR_SSL_KEY => "/etc/mysql/ssl/client-key.pem",
    PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true
];

// 建立连接
$pdo = new PDO($dsn, $username, $password, $options);

加密协议与 cipher 选择

1. 加密协议选择

  • TLS 1.3:推荐使用,提供更好的安全性和性能
  • TLS 1.2:兼容模式,支持较旧的客户端
  • 禁用 TLS 1.1 及以下:这些协议存在安全漏洞

2. 安全 cipher 套件

ini
# 推荐的 cipher 套件配置
ssl-cipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

3. 配置示例

ini
[mysqld]
# 启用 TLS 1.2 和 1.3
tls_version=TLSv1.2,TLSv1.3

# 配置安全 cipher 套件
ssl-cipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384

证书管理

1. 证书有效期监控

sql
-- 查看证书有效期
SHOW STATUS LIKE 'Ssl_server_not_after';

2. 证书轮换

服务器证书轮换

  1. 生成新的服务器证书
  2. 更新 MySQL 配置文件
  3. 重启 MySQL 服务
  4. 验证新证书生效

客户端证书轮换

  1. 生成新的客户端证书
  2. 分批次更新客户端配置
  3. 验证客户端连接正常

3. 证书撤销

  • 维护证书撤销列表(CRL)
  • 配置 MySQL 使用 CRL
ini
[mysqld]
# 配置 CRL
ssl-crl=/etc/mysql/ssl/ca-crl.pem

加密性能优化

1. 硬件加速

  • 确保服务器支持 AES-NI 硬件加速
  • 验证硬件加速是否启用
bash
# 检查 AES-NI 支持
grep -m1 -o aes /proc/cpuinfo

2. 连接池配置

  • 使用连接池减少 SSL 握手开销
  • 调整连接池参数优化性能

3. 选择性加密

  • 对于内部网络通信,可根据安全需求决定是否启用加密
  • 对于外部网络通信,强制使用加密

安全最佳实践

1. 证书安全

  • 定期更换证书(建议每年)
  • 使用强密钥长度(至少 2048 位)
  • 保护私钥文件不被未授权访问
  • 使用商业 CA 证书或内部 CA 基础设施

2. 配置安全

  • 强制客户端使用 SSL 连接
  • 禁用旧版加密协议
  • 使用安全的 cipher 套件
  • 定期审计 SSL 配置

3. 监控与审计

  • 监控 SSL 连接状态
  • 审计 SSL 配置变更
  • 记录 SSL 连接日志

常见问题(FAQ)

Q1: 如何验证 MySQL 连接是否使用了 SSL?

A1: 可以通过以下方式验证:

sql
-- 方法1:查看连接状态
SHOW STATUS LIKE 'Ssl_cipher';

-- 方法2:查看会话变量
SELECT @@session.ssl_cipher;

-- 方法3:从客户端验证
mysql -u root -p -e "status" | grep SSL

Q2: 启用 SSL 会影响 MySQL 性能吗?

A2: 启用 SSL 会带来一定的性能开销,主要体现在:

  • SSL 握手过程的额外开销
  • 数据加密和解密的 CPU 消耗

但在现代硬件上,这种开销通常在可接受范围内,特别是启用硬件加速后。对于对安全性要求高的场景,建议启用 SSL。

Q3: 如何强制所有客户端使用 SSL 连接?

A3: 可以通过以下两种方式:

  1. 在配置文件中设置:

    ini
    [mysqld]
    require_secure_transport=ON
  2. 为用户设置 REQUIRE SSL 选项:

    sql
    ALTER USER 'user'@'host' REQUIRE SSL;

Q4: 如何配置 MySQL 复制使用 SSL?

A4: 主从复制使用 SSL 的配置步骤:

  1. 在主从服务器上都配置 SSL
  2. 在主服务器上创建复制用户并要求 SSL:
    sql
    CREATE USER 'repl'@'slave_host' IDENTIFIED BY 'password' REQUIRE SSL;
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'slave_host';
  3. 在从服务器上配置复制连接使用 SSL:
    sql
    CHANGE MASTER TO
        MASTER_HOST='master_host',
        MASTER_USER='repl',
        MASTER_PASSWORD='password',
        MASTER_SSL=1,
        MASTER_SSL_CA='/etc/mysql/ssl/ca.pem',
        MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem',
        MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem';

Q5: 如何处理 SSL 证书过期问题?

A5: 处理证书过期的建议:

  1. 提前监控证书有效期,设置告警
  2. 在证书过期前生成新证书
  3. 制定证书轮换计划,避免业务中断
  4. 对于集群环境,分批次更新证书

Q6: 可以同时支持加密和非加密连接吗?

A6: 是的,MySQL 支持同时处理加密和非加密连接。可以通过以下方式配置:

  • 不设置 require_secure_transport=ON
  • 为需要加密的用户设置 REQUIRE SSL
  • 其他用户可以选择是否使用 SSL 连接

Q7: 如何选择合适的加密协议版本?

A7: 加密协议版本选择建议:

  • 优先使用 TLS 1.3,提供最好的安全性和性能
  • 兼容模式下同时支持 TLS 1.2 和 TLS 1.3
  • 禁用 TLS 1.1 及以下版本,这些协议存在安全漏洞

Q8: 自签名证书和商业证书有什么区别?

A8: 主要区别:

特性自签名证书商业证书
颁发机构自己生成可信 CA 机构
信任度需要手动信任被广泛信任
成本免费收费
有效期可自定义通常 1-3 年
适用场景内部测试、开发环境生产环境、对外服务

Q9: 如何配置 MySQL Workbench 使用 SSL 连接?

A9: MySQL Workbench SSL 配置步骤:

  1. 打开 MySQL Workbench
  2. 新建或编辑连接
  3. 在"SSL"标签页中:
    • 选择"Require SSL"
    • 浏览并选择 CA 证书、客户端证书和客户端私钥文件
  4. 测试连接,确认 SSL 连接成功

Q10: 启用 SSL 后如何排查连接问题?

A10: 排查 SSL 连接问题的方法:

  1. 检查 MySQL 错误日志
  2. 验证证书文件权限和路径
  3. 验证证书有效期和完整性
  4. 检查加密协议和 cipher 套件配置
  5. 使用 openssl s_client 测试 SSL 连接:
    bash
    openssl s_client -connect localhost:3306 -CAfile /etc/mysql/ssl/ca.pem
  6. 检查客户端 SSL 配置是否正确

案例分析

案例1:生产环境 SSL 配置

场景描述

某金融机构需要为生产环境的 MySQL 数据库启用 SSL 加密,确保客户端与服务器之间的通信安全。

解决方案

  1. 证书管理

    • 使用内部 CA 基础设施生成证书
    • 配置证书有效期为 2 年
    • 建立证书轮换机制
  2. 服务器配置

    ini
    [mysqld]
    ssl-ca=/etc/mysql/ssl/ca.pem
    ssl-cert=/etc/mysql/ssl/server-cert.pem
    ssl-key=/etc/mysql/ssl/server-key.pem
    tls_version=TLSv1.2,TLSv1.3
    ssl-cipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    require_secure_transport=ON
  3. 客户端配置

    • 所有应用程序配置 SSL 连接
    • 使用连接池减少 SSL 握手开销
    • 定期更新客户端证书
  4. 监控与审计

    • 监控证书有效期
    • 审计 SSL 连接日志
    • 定期检查 SSL 配置

实施效果

  • 所有客户端连接强制使用 SSL 加密
  • 加密通信性能开销控制在 5% 以内
  • 满足金融行业合规要求
  • 提高了数据传输的安全性

案例2:复制架构 SSL 配置

场景描述

某电商平台的 MySQL 主从复制架构需要启用 SSL 加密,确保主从服务器之间的数据传输安全。

解决方案

  1. 证书配置

    • 在主从服务器上部署相同的 CA 证书
    • 为主从服务器分别生成证书
  2. 主服务器配置

    sql
    -- 创建复制用户并要求 SSL
    CREATE USER 'repl'@'%' IDENTIFIED BY 'strong_password' REQUIRE SSL;
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
  3. 从服务器配置

    sql
    -- 配置复制连接使用 SSL
    CHANGE MASTER TO
        MASTER_HOST='master.example.com',
        MASTER_USER='repl',
        MASTER_PASSWORD='strong_password',
        MASTER_SSL=1,
        MASTER_SSL_CA='/etc/mysql/ssl/ca.pem',
        MASTER_SSL_CERT='/etc/mysql/ssl/client-cert.pem',
        MASTER_SSL_KEY='/etc/mysql/ssl/client-key.pem';
  4. 验证配置

    sql
    -- 在从服务器上验证 SSL 复制
    SHOW SLAVE STATUS\G

实施效果

  • 主从复制通信使用 SSL 加密
  • 复制延迟无明显增加
  • 提高了复制架构的安全性
  • 满足了合规要求