Skip to content

MySQL SSL/TLS配置

SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是用于在网络通信中提供加密和身份验证的安全协议。在MySQL中启用SSL/TLS可以:

  • 加密客户端和服务器之间的通信数据
  • 验证服务器的身份,防止中间人攻击
  • 可选地验证客户端身份
  • 满足合规性要求(如PCI DSS)

证书生成

1. 使用自签名证书

自签名证书适合测试环境或内部使用,不适合生产环境。

  • 生成CA证书

    bash
    # 创建CA私钥
    openssl genrsa 2048 > ca-key.pem
    
    # 生成CA证书
    openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem
  • 生成服务器证书

    bash
    # 生成服务器私钥
    openssl genrsa 2048 > server-key.pem
    
    # 生成证书签名请求(CSR)
    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 -out server-cert.pem
  • 生成客户端证书

    bash
    # 生成客户端私钥
    openssl genrsa 2048 > client-key.pem
    
    # 生成客户端CSR
    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 -out client-cert.pem
  • 转换证书格式

    bash
    # 转换服务器私钥为PEM格式
    openssl rsa -in server-key.pem -out server-key.pem
    
    # 转换客户端私钥为PEM格式
    openssl rsa -in client-key.pem -out client-key.pem

2. 使用商业CA证书

生产环境建议使用受信任的商业CA颁发的证书。

  • 获取证书

    • 从商业CA(如DigiCert、Let's Encrypt等)申请证书
    • 按照CA提供商的指示生成CSR并获取证书
    • 确保证书链完整
  • 证书文件

    • 服务器证书(.pem格式)
    • 服务器私钥(.pem格式)
    • CA证书链(.pem格式)

服务器配置

1. 基本配置

  • 配置文件修改

    ini
    [mysqld]
    # SSL配置
    ssl-ca=/path/to/ca.pem
    ssl-cert=/path/to/server-cert.pem
    ssl-key=/path/to/server-key.pem
    
    # 强制所有连接使用SSL
    # require_secure_transport=ON
    
    # 可选:只允许特定加密协议
    # ssl-cipher=TLSv1.2,TLSv1.3
  • 重启MySQL服务

    bash
    # systemd系统
    systemctl restart mysqld
    
    # SysV init系统
    service mysqld restart

2. 验证SSL配置

  • 检查SSL是否启用

    sql
    SHOW VARIABLES LIKE '%ssl%';
  • 预期输出

    sql
    +---------------------+---------------------------+
    | Variable_name       | Value                     |
    +---------------------+---------------------------+
    | have_ssl            | YES                       |
    | ssl_ca              | /path/to/ca.pem           |
    | ssl_cert            | /path/to/server-cert.pem  |
    | ssl_key             | /path/to/server-key.pem   |
    | ssl_version         | TLSv1.2,TLSv1.3           |
    +---------------------+---------------------------+

3. 用户权限配置

  • 创建要求SSL的用户

    sql
    -- 创建用户并要求SSL
    CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
    
    -- 创建用户并要求特定客户端证书
    CREATE USER 'cert_user'@'%' IDENTIFIED BY 'password' REQUIRE X509;
    
    -- 授予权限
    GRANT ALL PRIVILEGES ON *.* TO 'ssl_user'@'%';
    GRANT ALL PRIVILEGES ON *.* TO 'cert_user'@'%';
    
    -- 刷新权限
    FLUSH PRIVILEGES;
  • 查看用户SSL要求

    sql
    SELECT user, host, ssl_type FROM mysql.user WHERE user IN ('ssl_user', 'cert_user');

客户端配置

1. 基本连接配置

  • 使用命令行客户端连接

    bash
    # 基本SSL连接
    mysql -u ssl_user -p -h hostname --ssl
    
    # 使用特定证书连接
    mysql -u cert_user -p -h hostname \
      --ssl-ca=/path/to/ca.pem \
      --ssl-cert=/path/to/client-cert.pem \
      --ssl-key=/path/to/client-key.pem
  • 验证连接是否使用SSL

    sql
    SHOW STATUS LIKE 'Ssl_cipher';
  • 预期输出

    sql
    +---------------+--------------------+
    | Variable_name | Value              |
    +---------------+--------------------+
    | Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
    +---------------+--------------------+

2. 应用程序连接配置

  • PHP PDO配置

    php
    $dsn = "mysql:host=hostname;dbname=database;charset=utf8mb4";
    $options = [
        PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem',
        PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem',
        PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem',
        PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true
    ];
    $pdo = new PDO($dsn, 'ssl_user', 'password', $options);
  • Java JDBC配置

    java
    String url = "jdbc:mysql://hostname:3306/database?useSSL=true&requireSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file:/path/to/truststore.jks&trustCertificateKeyStorePassword=password";
    Connection conn = DriverManager.getConnection(url, "ssl_user", "password");
  • Python MySQL Connector配置

    python
    import mysql.connector
    
    config = {
        'user': 'ssl_user',
        'password': 'password',
        'host': 'hostname',
        'database': 'database',
        'ssl_ca': '/path/to/ca.pem',
        'ssl_cert': '/path/to/client-cert.pem',
        'ssl_key': '/path/to/client-key.pem'
    }
    
    conn = mysql.connector.connect(**config)

3. 连接池配置

  • HikariCP配置

    properties
    # HikariCP SSL配置
    spring.datasource.hikari.data-source-properties.useSSL=true
    spring.datasource.hikari.data-source-properties.requireSSL=true
    spring.datasource.hikari.data-source-properties.verifyServerCertificate=true
    spring.datasource.hikari.data-source-properties.sslCA=/path/to/ca.pem
    spring.datasource.hikari.data-source-properties.sslCert=/path/to/client-cert.pem
    spring.datasource.hikari.data-source-properties.sslKey=/path/to/client-key.pem
  • Druid配置

    properties
    # Druid SSL配置
    spring.datasource.druid.url=jdbc:mysql://hostname:3306/database?useSSL=true&requireSSL=true&verifyServerCertificate=true
    spring.datasource.druid.username=ssl_user
    spring.datasource.druid.password=password
    spring.datasource.druid.connection-properties=sslCA=/path/to/ca.pem;sslCert=/path/to/client-cert.pem;sslKey=/path/to/client-key.pem

不同MySQL版本的差异

MySQL 5.7 vs 8.0

  • 默认配置差异

    • MySQL 5.7:默认不启用SSL
    • MySQL 8.0:默认启用SSL(使用自签名证书)
  • 加密协议支持

    • MySQL 5.7:支持TLSv1, TLSv1.1, TLSv1.2
    • MySQL 8.0:支持TLSv1, TLSv1.1, TLSv1.2, TLSv1.3(默认禁用TLSv1, TLSv1.1)
  • 证书管理

    • MySQL 8.0:新增了mysql_ssl_rsa_setup工具,简化证书生成
    • MySQL 8.0:支持动态修改SSL配置(无需重启服务)

MySQL 8.0 小版本差异

  • TLSv1.3支持

    • MySQL 8.0.16+:正式支持TLSv1.3
    • MySQL 8.0.26+:默认启用TLSv1.3
  • 加密算法

    • 后续版本新增了更多安全的加密算法
    • 移除了一些不安全的加密算法

性能考虑

1. 加密对性能的影响

  • CPU开销:加密和解密操作会增加CPU负载,通常增加5-15%
  • 网络带宽:加密数据会增加数据大小,通常增加5-10%
  • 连接建立时间:SSL握手会增加连接建立时间

2. 性能优化建议

  • 使用硬件加速:确保CPU支持AES-NI指令集,提高加密性能
  • 合理配置加密协议:只启用安全的加密协议(如TLSv1.2, TLSv1.3)
  • 优化连接池:增加连接池大小,减少连接建立频率
  • 选择性加密:只对敏感数据或外部连接使用SSL

安全最佳实践

1. 证书管理

  • 定期更新证书:证书到期前及时更新
  • 安全存储私钥:限制私钥文件的访问权限(chmod 600)
  • 使用强密码保护私钥
  • 建立证书撤销机制

2. 配置最佳实践

  • 禁用不安全的协议:只启用TLSv1.2和TLSv1.3
  • 使用强加密算法:如AES-256-GCM, CHACHA20-POLY1305
  • 强制敏感用户使用SSL
  • 定期检查SSL配置:使用工具如openssl s_client检查SSL配置

3. 监控和审计

  • 监控SSL连接数

    sql
    SHOW GLOBAL STATUS LIKE 'Ssl%';
  • 审计SSL连接

    sql
    -- 启用审计日志
    SET GLOBAL audit_log=ON;
    SET GLOBAL audit_log_format=JSON;

常见问题(FAQ)

Q1: MySQL 8.0默认启用SSL,如何禁用?

A1: 可以通过修改配置文件禁用SSL:

ini
[mysqld]
skip_ssl

然后重启MySQL服务。

Q2: 如何检查MySQL服务器支持的SSL加密算法?

A2: 使用openssl s_client工具:

bash
openssl s_client -connect hostname:3306 -tls1_2 < /dev/null 2>/dev/null | grep -A 10 "Cipher Suites"

Q3: 客户端连接时出现"SSL connection error: SSL_CTX_set_default_verify_paths failed"怎么办?

A3: 这个错误通常是因为客户端找不到CA证书。解决方法:

  • 确保指定了正确的CA证书路径
  • 使用--ssl-ca参数指定CA证书
  • 对于自签名证书,可以使用--ssl-mode=VERIFY_CA--ssl-mode=VERIFY_IDENTITY

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

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

  1. 确保主库和从库都已启用SSL
  2. 在主库创建复制用户并要求SSL:
    sql
    CREATE USER 'repl'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
    GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
  3. 在从库配置复制连接:
    sql
    CHANGE MASTER TO
      MASTER_HOST='master_host',
      MASTER_USER='repl',
      MASTER_PASSWORD='password',
      MASTER_SSL=1,
      MASTER_SSL_CA='/path/to/ca.pem',
      MASTER_SSL_CERT='/path/to/client-cert.pem',
      MASTER_SSL_KEY='/path/to/client-key.pem';

Q5: 如何验证客户端连接确实使用了SSL?

A5: 在MySQL客户端中执行:

sql
SHOW STATUS LIKE 'Ssl_cipher';

如果返回非空值,表示连接使用了SSL。

Q6: MySQL SSL配置后,性能下降明显怎么办?

A6: 可以尝试以下优化措施:

  • 确保CPU支持AES-NI硬件加速
  • 升级到MySQL 8.0,享受更好的SSL性能
  • 只对外部连接或敏感用户启用SSL
  • 优化连接池配置,减少连接建立频率
  • 使用更高效的加密算法,如TLSv1.3

Q7: 如何使用Let's Encrypt证书配置MySQL SSL?

A7: 步骤如下:

  1. 使用Certbot获取Let's Encrypt证书
  2. 将证书复制到MySQL配置目录
  3. 修改MySQL配置文件:
    ini
    [mysqld]
    ssl-ca=/etc/letsencrypt/live/example.com/chain.pem
    ssl-cert=/etc/letsencrypt/live/example.com/cert.pem
    ssl-key=/etc/letsencrypt/live/example.com/privkey.pem
  4. 重启MySQL服务

Q8: MySQL 5.7如何启用TLSv1.3?

A8: MySQL 5.7不支持TLSv1.3,需要升级到MySQL 8.0.16或更高版本才能使用TLSv1.3。

故障排查

1. 常见错误及解决方法

  • 错误1:"SSL connection error: certificate verify failed"

    • 原因:客户端无法验证服务器证书
    • 解决方法:确保客户端信任服务器证书,或使用--ssl-mode=DISABLED临时绕过验证
  • 错误2:"SSL connection error: wrong version number"

    • 原因:客户端和服务器使用的SSL协议版本不匹配
    • 解决方法:指定正确的SSL协议版本,如--ssl-version=TLSv1.2
  • 错误3:"Access denied for user 'user'@'host' (using password: YES)"

    • 原因:用户要求SSL但连接未使用SSL
    • 解决方法:确保客户端连接时使用了--ssl参数

2. 诊断工具

  • openssl s_client:检查服务器SSL配置

    bash
    openssl s_client -connect hostname:3306 -tls1_2
  • mysql_ssl_rsa_setup:生成SSL证书(MySQL 5.7+)

    bash
    mysql_ssl_rsa_setup --datadir=/path/to/data
  • SHOW VARIABLES:查看MySQL SSL配置

    sql
    SHOW VARIABLES LIKE '%ssl%';