MySQL主从复制中从库连接主库的安全性问题及解决方案

1 次阅读

MySQL主从复制的核心机制,是从库通过复制连接持续读取主库的 Binlog,并将日志传输到本地后进行重放。这个连接本身承担着数据同步的重要职责,因此很多环境在关注“能不能同步”的同时,却忽略了“复制连接是否安全”。

如果从库使用明文账号密码连接主库、复制账号权限过大、网络端口直接暴露公网,或者没有启用传输加密,那么一旦网络链路或账号凭据遭到攻击,主从复制就可能从数据同步通道变成安全风险入口。

MySQL主从复制连接存在哪些安全风险

传统主从复制配置通常需要在主库创建复制账号,例如:

SQL
CREATE USER 'repl'@'192.168.10.%' IDENTIFIED BY 'StrongPassword123!';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.%';

从库再通过类似配置连接:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='192.168.10.10',
    SOURCE_PORT=3306,
    SOURCE_USER='repl',
    SOURCE_PASSWORD='StrongPassword123!',
    SOURCE_LOG_FILE='mysql-bin.000001',
    SOURCE_LOG_POS=1234;

这种方式能够完成复制,但从安全角度来看至少存在几个值得注意的问题。

1. 复制账号密码可能泄露

复制连接必须进行身份认证。如果密码直接出现在命令历史、配置文件、自动化脚本或者运维文档中,就可能造成凭据泄露。

尤其是在使用 Shell 脚本自动配置复制时:

Bash
mysql -uroot -p'RootPassword'

或者:

Bash
mysql -h 192.168.10.10 -u repl -p'ReplPassword'

都存在较明显的密码暴露风险。

2. 复制流量可能被窃听

如果主库和从库之间通过普通 TCP 连接进行复制,而没有启用 TLS 加密,那么网络链路上的数据存在被监听的可能。

主从复制传输的不只是简单的状态信息,还涉及 Binlog 内容。根据业务类型,Binlog 中可能包含大量数据库变更信息。

因此,即使复制账号权限有限,也不能忽略传输过程中的数据保护。

3. 复制账号权限过大

复制账号只需要执行复制相关操作,却经常被错误地授予:

SQL
GRANT ALL PRIVILEGES ON *.* TO 'repl'@'%';

这相当于把数据库管理权限直接交给了复制账号。

一旦账号密码泄露,攻击者可能利用该账号进一步读取、修改甚至删除数据。

4. 主库3306端口暴露范围过大

如果主库监听:

INI
bind-address = 0.0.0.0

同时防火墙允许任意地址访问3306端口,那么主库数据库服务实际上暴露在较大的网络范围内。

更合理的做法是让主库只接受来自指定从库服务器的连接。

5. 使用过于宽泛的Host匹配规则

例如:

SQL
'repl'@'%'

表示允许任意来源主机尝试使用这个账号连接。

如果只是为了让某一台从库进行复制,显然没有必要开放给所有地址。


复制账号应该遵循最小权限原则

主从复制安全加固的第一步,就是重新审视复制账号权限。

MySQL 8.0环境可以创建专用复制账号:

SQL
CREATE USER 'repl'@'192.168.10.20'
IDENTIFIED BY '生成一个高强度随机密码';

GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.20';

对于使用 GTID 的现代MySQL环境,也可以根据实际版本和复制架构授予复制所需的最小权限。

查看账号权限:

SQL
SHOW GRANTS FOR 'repl'@'192.168.10.20';

理想情况下,输出结果应该只包含复制所需权限,而不是:

ALL PRIVILEGES

为什么不能直接使用root账号复制

部分早期教程为了方便,会直接使用root或高权限账号作为复制账号。

这种做法不推荐。

假设root账号同时承担:

  • 数据库管理

  • 主从复制

  • 应用访问

  • 日常运维

那么其中任意一个场景发生凭据泄露,都可能导致整个数据库实例失守。

更合理的架构是:

root/admin
   │
   ├── 数据库管理
   │
   └── 账号权限管理

repl
   │
   └── 仅负责主从复制

让不同账号承担不同职责,可以明显缩小安全事件的影响范围。


限制复制账号的来源地址

复制账号的Host定义非常关键。

不推荐:

SQL
CREATE USER 'repl'@'%' IDENTIFIED BY '密码';

更推荐明确指定从库IP:

SQL
CREATE USER 'repl'@'192.168.10.20'
IDENTIFIED BY '高强度密码';

GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.20';

如果存在多台从库,也可以分别建立账号:

SQL
CREATE USER 'repl01'@'192.168.10.20' IDENTIFIED BY '密码1';
CREATE USER 'repl02'@'192.168.10.21' IDENTIFIED BY '密码2';

GRANT REPLICATION SLAVE ON *.* TO 'repl01'@'192.168.10.20';
GRANT REPLICATION SLAVE ON *.* TO 'repl02'@'192.168.10.21';

这样做的优势在于,一台从库发生安全事件时,可以单独禁用对应账号,而不会影响其他复制节点。


使用TLS加密主从复制连接

如果主库和从库之间跨越不同网络区域,或者网络环境无法完全信任,建议启用TLS。

首先需要准备:

  • CA证书

  • 主库服务器证书

  • 主库服务器私钥

  • 从库客户端证书(根据安全策略决定是否使用)

  • 对应的证书权限

MySQL服务端可以配置类似:

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

修改配置后重启MySQL,并确认TLS状态。

可以执行:

SQL
SHOW VARIABLES LIKE 'have_ssl';

以及:

SQL
SHOW VARIABLES LIKE 'ssl_%';

不同MySQL版本在TLS相关变量和配置方式上可能存在差异,因此实际部署时应以当前版本官方文档为准。


强制复制连接使用SSL

仅仅让MySQL支持TLS并不意味着复制连接一定使用TLS。

创建复制账号时,可以要求该账号必须通过SSL连接:

SQL
CREATE USER 'repl'@'192.168.10.20'
IDENTIFIED BY '高强度密码'
REQUIRE SSL;

GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.10.20';

也可以对已有账号进行修改:

SQL
ALTER USER 'repl'@'192.168.10.20'
REQUIRE SSL;

然后从库连接主库时指定SSL相关参数。

以较新的MySQL语法为例:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='192.168.10.10',
    SOURCE_PORT=3306,
    SOURCE_USER='repl',
    SOURCE_PASSWORD='高强度密码',
    SOURCE_SSL=1,
    SOURCE_LOG_FILE='mysql-bin.000001',
    SOURCE_LOG_POS=1234;

如果使用GTID复制,可以结合当前版本语法配置:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='192.168.10.10',
    SOURCE_PORT=3306,
    SOURCE_USER='repl',
    SOURCE_PASSWORD='高强度密码',
    SOURCE_SSL=1,
    SOURCE_AUTO_POSITION=1;

老版本MySQL通常使用:

SQL
CHANGE MASTER TO
    MASTER_HOST='192.168.10.10',
    MASTER_PORT=3306,
    MASTER_USER='repl',
    MASTER_PASSWORD='高强度密码',
    MASTER_SSL=1;

这里需要特别注意,CHANGE MASTER TOCHANGE REPLICATION SOURCE TO 的命令名称与MySQL版本有关。配置生产环境时不要直接复制其他版本的命令。


使用证书验证主库身份

单纯使用加密可以防止数据被直接窃听,但更严格的安全策略还应该考虑服务器身份验证。

例如,可以配置CA:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='mysql-master.example.com',
    SOURCE_USER='repl',
    SOURCE_PASSWORD='高强度密码',
    SOURCE_SSL=1,
    SOURCE_SSL_CA='/etc/mysql/ssl/ca.pem';

对于要求更高的环境,可以进一步使用客户端证书:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_SSL=1,
    SOURCE_SSL_CA='/etc/mysql/ssl/ca.pem',
    SOURCE_SSL_CERT='/etc/mysql/ssl/client-cert.pem',
    SOURCE_SSL_KEY='/etc/mysql/ssl/client-key.pem';

这样可以形成更加完整的TLS身份认证体系。

证书文件本身也必须做好权限控制,例如避免普通系统用户读取数据库私钥。


不要把复制密码随意写进脚本

复制配置中的密码属于敏感凭据。

不推荐把密码直接硬编码到:

Bash
replication.sh

或者:

docker-compose.yml

以及公开的Git仓库中。

尤其要注意:

Bash
history

可能保留包含密码的命令。

更合理的方式包括使用MySQL提供的登录路径机制、受控的配置文件或者专门的密钥管理系统。

例如可以使用:

Bash
mysql_config_editor set 
  --login-path=replication 
  --host=192.168.10.10 
  --user=repl 
  --password

随后使用:

Bash
mysql --login-path=replication

避免在Shell命令行中直接暴露密码。

需要注意的是,mysql_config_editor 并不意味着凭据完全不需要保护。生成的登录路径文件仍然应该限制文件权限,并纳入服务器安全管理体系。


使用防火墙限制3306访问范围

数据库层面的权限控制和网络层面的访问控制应该同时存在。

假设:

主库:192.168.10.10
从库:192.168.10.20

那么主库防火墙可以只允许:

192.168.10.20 → 192.168.10.10:3306

而不是:

0.0.0.0/0 → 3306

Linux环境可以结合iptables、nftables、firewalld等工具实施访问控制。

例如使用firewalld时,可以根据实际网络环境设置来源IP:

Bash
firewall-cmd --permanent 
  --add-rich-rule='rule family="ipv4" source address="192.168.10.20" port protocol="tcp" port="3306" accept'

firewall-cmd --reload

实际生产环境还应该结合默认拒绝策略检查现有规则,避免其他规则意外放行3306。


不要直接把MySQL暴露到公网

如果主库和从库位于不同云环境或者不同数据中心,不建议简单地通过公网IP开放3306。

更安全的网络结构通常是:

从库
  │
  │ VPN / 专线 / 私有网络
  ▼
安全网络区域
  │
  ▼
主库

如果必须经过公网,则至少应该同时考虑:

  • TLS加密

  • 防火墙白名单

  • 安全组限制

  • 强密码

  • 最小权限

  • 访问日志

  • 异常连接监控

网络安全与数据库权限控制属于不同防线,不能认为开启其中一种措施就可以替代另一种。


检查复制连接是否真的使用加密

完成配置后,不应该只看配置文件,而应该验证实际复制连接状态。

可以查看复制状态:

SQL
SHOW REPLICA STATUSG

老版本:

SQL
SHOW SLAVE STATUSG

重点关注:

Replica_IO_Running: Yes
Replica_SQL_Running: Yes

或者旧版本中的:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

同时检查TLS相关状态。

MySQL客户端也可以通过:

SQL
STATUS;

查看当前连接是否使用SSL/TLS。

如果是从库复制连接,则应该结合当前MySQL版本提供的复制状态字段和连接信息进行确认,而不能仅凭“配置文件中写了SSL”判断已经完成加密。


进一步开启复制链路的安全保护

除了连接加密之外,还可以从复制架构本身增强安全性。

1. 使用GTID复制

GTID能够让复制拓扑管理更加清晰,也便于故障切换和重新建立复制关系。

例如:

SQL
CHANGE REPLICATION SOURCE TO
    SOURCE_AUTO_POSITION=1;

不过GTID本身不是加密技术,不能因为使用GTID就认为复制链路已经安全。

2. 启用Binlog校验

可以根据MySQL版本和业务需求配置Binlog相关校验机制,用于降低日志传输过程中发生静默损坏的风险。

需要明确的是,数据完整性校验和数据保密是两个不同的问题:

完整性 → 防止数据被错误修改或损坏
保密性 → 防止数据被未授权读取

TLS主要解决后者,同时也提供传输完整性保护。

3. 对复制账号进行定期轮换

复制账号密码不应该永久不变。

可以制定周期性的密码轮换策略,并在切换前规划好主从复制连接的变更步骤,避免直接修改密码导致复制中断。


常见错误配置及改进方式

错误一:复制账号使用root

SQL
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

**问题:**权限过高,凭据泄露后的破坏范围非常大。

**改进:**建立独立复制账号,只授予复制所需权限。


错误二:复制账号使用%

SQL
'repl'@'%'

**问题:**任何能够访问MySQL端口的主机都可能尝试使用该账号认证。

改进:

SQL
'repl'@'192.168.10.20'

根据实际从库IP进行限制。


错误三:主库3306向公网开放

0.0.0.0/0 → TCP 3306

**问题:**攻击面明显扩大。

**改进:**使用私有网络、VPN、专线或严格的安全组和防火墙白名单。


错误四:只设置SSL变量,不验证复制连接

**问题:**服务端支持TLS并不代表复制连接一定正在使用TLS。

**改进:**完成配置后检查复制状态、连接状态以及TLS相关信息。


错误五:密码写入Git仓库

例如:

YAML
SOURCE_PASSWORD: "MyPassword123"

**问题:**即使后来删除文件,Git历史中也可能保留密码。

**改进:**使用密钥管理系统、受保护的配置文件或者MySQL登录路径,并对已经泄露的凭据立即进行轮换。


一套较完整的安全配置思路

生产环境可以按照下面的思路设计:

                 ┌──────────────┐
                 │   主数据库    │
                 │ 192.168.10.10│
                 └──────┬───────┘
                        │
                 TLS加密复制连接
                        │
                 ┌──────▼───────┐
                 │   从数据库    │
                 │ 192.168.10.20│
                 └──────────────┘

网络层:
只允许 192.168.10.20 → 3306

数据库层:
repl@192.168.10.20

权限层:
仅授予复制所需权限

传输层:
强制TLS

凭据层:
强密码 + 安全存储 + 定期轮换

审计层:
连接日志 + 异常访问监控

这种设计的核心并不是单独依赖某一项安全措施,而是建立多层防护。

即使攻击者绕过其中一道防线,后续的网络限制、账号权限和TLS机制仍然可以降低风险。

MySQL主从复制安全检查清单

正式上线之前,可以按照下面的清单逐项检查:

  • 是否创建独立的复制账号

  • 是否避免使用root作为复制账号

  • 复制账号是否遵循最小权限原则

  • 是否限制复制账号Host来源

  • 主库3306是否只允许必要服务器访问

  • 是否避免公网直接暴露MySQL

  • 主从之间是否使用TLS

  • 是否验证复制连接确实使用TLS

  • CA、证书和私钥是否妥善保存

  • 复制密码是否避免硬编码

  • 是否避免密码进入Shell历史和Git仓库

  • 是否建立复制账号密码轮换机制

  • 是否持续监控复制连接状态

  • 是否对异常登录和网络访问进行审计

主从复制的安全性并不只取决于“密码够不够复杂”。真正可靠的方案应该同时覆盖身份认证、权限控制、网络隔离、传输加密、凭据保护和运行监控

对于同一内网中的数据库服务器,至少应该做到复制账号最小权限、来源IP限制以及防火墙白名单;如果跨公网、跨数据中心或跨安全域进行复制,则应进一步采用TLS、VPN、专线或其他可信网络通道。

只有把数据库权限和网络安全结合起来,才能真正降低MySQL主从复制连接被窃听、凭据泄露以及未授权访问带来的风险。