作为全球最流行的关系型数据库之一,MySQL凭借轻量、高效、开源的特性,广泛应用于中小型网站、企业级应用及云服务中。但随着其使用场景的普及,MySQL面临的安全风险也日益突出——口令破解、权限滥用、数据窃取、拒绝服务等攻击频发,一旦被攻陷,可能导致核心业务数据泄露、服务中断甚至系统被接管。本文基于CentOS 7环境,结合实战场景,从“风险定位-针对性加固-效果验证”三个维度,系统梳理MySQL数据库的安全加固方案,覆盖防口令破解、防服务漏洞、防权限滥用、防信息泄露、防拒绝服务五大核心场景,帮助技术人员构建MySQL安全防线。

一、MySQL安全风险与加固逻辑

在开展加固前,需先明确MySQL的核心安全风险点及对应防御思路。根据攻击链路,常见风险可分为五类,每类风险对应明确的加固目标:

攻击类型 典型攻击手段 加固核心目标
口令破解 暴力破解、字典攻击、默认口令滥用 消除弱口令、空口令、匿名访问,强化账号认证
服务漏洞 利用MySQL版本漏洞(如CVE-2022-21587)、未授权访问 关闭冗余服务、升级修复漏洞、限制服务暴露范围
权限提升 低权限账号滥用FILE权限写后门、root账号过度授权 遵循最小权限原则,禁用高危权限,限制账号操作范围
信息窃取 明文传输窃听、日志泄露敏感数据、未脱敏数据访问 加密数据传输,脱敏敏感字段,开启审计日志追踪
拒绝服务 海量空连接、复杂查询耗尽资源、连接数超限 限制连接资源,优化查询性能,拦截异常访问行为

本文的加固操作均基于CentOS 7 x64 + MySQL 5.7/MariaDB 10.2(与原实验环境兼容),所有操作需以root用户登录操作系统,MySQL管理员账号默认使用root(密码toor,实验环境初始配置)。

二、实战加固:五大场景的具体操作

2.1 防口令破解:从账号源头阻断攻击

口令是MySQL的第一道防线,大量攻击始于“弱口令/空口令/冗余账号”,需通过四步操作彻底清理风险账号:

(1)删除无关冗余账号

风险点:开发测试阶段创建的临时账号(如test)、废弃业务账号若未删除,可能被攻击者利用字典攻击破解。
操作步骤

  1. 登录MySQL,查看当前所有账号及访问主机:
    mysql -uroot -p  # 输入密码toor登录
    select user, host from mysql.user;  # 列出所有账号
    
    执行后若发现test账号(访问主机为%,即允许任意IP登录),需立即删除。
  2. 删除冗余账号并刷新权限:
    drop user 'test'@'%';  # 注意指定host,避免误删同名不同主机的账号
    flush privileges;  # 刷新权限表,使修改生效
    quit;  # 退出MySQL
    
  3. 验证结果:再次执行select user, host from mysql.user;,确认test账号已消失。
(2)清理空口令账号

风险点:空口令账号(如stuff1)无需密码即可登录,攻击者可直接通过该账号访问数据库。
操作步骤

  1. 排查空口令账号:
    mysql -uroot -p
    select user, password from mysql.user where length(password)=0 or password is null;
    
    若输出stuff1账号,说明存在空口令风险。
  2. 删除空口令账号:
    drop user 'stuff1'@'%';  # 按实际host调整,若为localhost则写'localhost'
    flush privileges;
    quit;
    
  3. 验证:再次执行空口令排查命令,确认无结果返回。
(3)升级弱口令账号

风险点:弱口令(如123456abcdef)易被暴力破解工具(如Hydra)在几分钟内破解,需替换为强口令。
操作步骤

  1. 定位弱口令账号:通过业务文档或select user from mysql.user;确认需加固的账号(如dbuser1)。
  2. 修改为强口令(需满足:大小写字母+数字+特殊符号,长度≥10位):
    mysql -uroot -p
    # MySQL 5.7及以下用password()函数,8.0+用authentication_string字段
    update mysql.user set password=password('Eef9ch@oh-2025') where user='dbuser1' and host='%';
    flush privileges;
    quit;
    
  3. 验证:使用新密码登录测试,确认账号可用:
    mysql -udbuser1 -p'Eef9ch@oh-2025'  # 若能正常登录则修改成功
    
(4)删除匿名账号

风险点:MySQL默认可能存在匿名账号(无用户名或用户名为空),允许攻击者无需账号即可登录数据库(仅能访问test库或无权限),但可能作为“跳板”进一步探测漏洞。
操作步骤

  1. 排查匿名账号:
    mysql -uroot -p
    select user, host from mysql.user where user='';  # 匿名账号的user字段为空
    
  2. 删除匿名账号:
    drop user ''@'localhost';  # 匿名账号通常仅允许本地登录,host为localhost
    drop user ''@'::1';  # 若存在IPv6匿名账号,需一并删除
    flush privileges;
    quit;
    
  3. 验证:再次执行匿名账号排查命令,确认无结果。

2.2 防服务漏洞:缩小攻击面,修复已知风险

MySQL服务本身的漏洞(如版本漏洞、默认端口暴露)是攻击者的重要突破口,需通过“漏洞修复+服务硬化”双重防护:

(1)升级MySQL至安全版本

风险点:旧版本MySQL可能存在高危漏洞(如CVE-2022-21587,影响MySQL 8.0.29及以下版本,可导致远程代码执行)。
操作步骤

  1. 查看当前MySQL版本:
    mysql -uroot -p -e "select version();"  # 输出当前版本,如5.7.36
    
  2. 升级至官方推荐的安全版本(以CentOS 7 yum升级为例):
    # 备份数据库(避免升级丢失数据)
    mysqldump -uroot -p --all-databases > mysql_backup_$(date +%Y%m%d).sql
    # 停止MySQL服务
    systemctl stop mysqld
    # 升级MySQL(需先配置官方yum源,或使用第三方源如Remi)
    yum update mysql-server -y
    # 重启服务并设置开机自启
    systemctl start mysqld
    systemctl enable mysqld
    
  3. 验证:再次查看版本,确认已升级至无已知高危漏洞的版本(如MySQL 5.7.44、8.0.36+)。
(2)限制MySQL服务访问范围

风险点:MySQL默认监听3306端口,若对外开放,可能被外部攻击者扫描攻击;即使内网环境,也需限制仅业务服务器可访问。
操作步骤

  1. 配置防火墙,仅允许指定IP访问3306端口(如业务服务器IP为192.168.1.100):
    # 查看防火墙状态
    systemctl status firewalld
    # 允许192.168.1.100访问3306端口
    firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100/32" port protocol="tcp" port="3306" accept'
    # 移除全局3306端口允许规则(若存在)
    firewall-cmd --permanent --remove-port=3306/tcp
    # 重新加载防火墙规则
    firewall-cmd --reload
    
  2. 修改MySQL配置,禁止监听所有IP(仅监听业务网段IP):
    # 编辑MySQL配置文件(路径可能为/etc/my.cnf或/etc/mysql/my.cnf)
    vi /etc/my.cnf
    # 添加或修改bind-address参数,指定监听的IP(如192.168.1.50,MySQL服务器内网IP)
    bind-address = 192.168.1.50
    # 保存退出,重启MySQL服务
    systemctl restart mysqld
    
  3. 验证:在非授权IP(如192.168.1.200)上测试连接,确认无法访问:
    mysql -uroot -p -h 192.168.1.50  # 应提示"Access denied"或连接超时
    
(3)关闭不必要的服务功能

风险点:MySQL的某些默认功能(如Federated存储引擎、查询缓存)可能存在漏洞或性能风险,非必要场景下需禁用。
操作步骤

  1. 编辑MySQL配置文件,添加禁用冗余功能的参数:
    vi /etc/my.cnf
    # 禁用Federated存储引擎(可能被用于跨库攻击)
    skip-federated
    # 禁用查询缓存(MySQL 8.0已移除,5.7及以下版本建议禁用,避免性能问题和漏洞)
    query_cache_type = 0
    query_cache_size = 0
    # 禁用本地文件访问(防止低权限账号读取服务器文件)
    secure_file_priv = /dev/null
    
  2. 重启MySQL服务:
    systemctl restart mysqld
    
  3. 验证:登录MySQL,确认功能已禁用:
    # 查看存储引擎,确认Federated未启用
    show engines;
    # 查看查询缓存配置
    show variables like 'query_cache%';  # 应显示query_cache_type=0
    

2.3 防权限滥用:遵循最小权限原则

攻击者常通过“低权限账号提权”获取数据库控制权(如利用FILE权限写入后门文件),需通过权限精细化管控阻断提权路径:

(1)限制root账号远程登录

风险点root账号拥有MySQL最高权限,若允许远程登录,一旦口令泄露,攻击者可完全控制数据库。
操作步骤

  1. 查看root账号的访问主机:
    mysql -uroot -p
    select user, host from mysql.user where user='root';
    
    若存在root@'%'(允许任意IP远程登录),需修改为仅本地登录或特定管理IP登录。
  2. 修改root账号的访问主机(仅允许本地登录):
    # 删除允许远程登录的root账号
    drop user 'root'@'%';
    # 若需管理IP远程登录(如管理员IP为192.168.1.20),则创建限定IP的root账号
    create user 'root'@'192.168.1.20' identified by 'StrongRootPass@2025';
    grant all privileges on *.* to 'root'@'192.168.1.20' with grant option;
    flush privileges;
    quit;
    
  3. 验证:在非管理IP上测试root远程登录,确认无法访问。
(2)为业务账号配置最小权限

风险点:业务账号若被授予ALL PRIVILEGES(所有权限),一旦账号泄露,攻击者可修改、删除数据;需按“业务需求仅授予必要权限”。
操作步骤

  1. 以电商业务为例,创建仅能访问ecommerce库的shop_app账号,仅授予select(查询商品)、insert(新增订单)权限:
    mysql -uroot -p
    # 创建账号(仅允许业务服务器IP 192.168.1.100访问)
    create user 'shop_app'@'192.168.1.100' identified by 'ShopAppPass@2025';
    # 授予ecommerce库的select、insert权限(无update、delete、drop权限)
    grant select, insert on ecommerce.* to 'shop_app'@'192.168.1.100';
    flush privileges;
    
  2. 验证权限:登录shop_app账号,测试是否无法执行未授权操作:
    mysql -ushop_app -p'ShopAppPass@2025' -h 192.168.1.50
    drop table ecommerce.goods;  # 应提示"Access denied"
    
(3)禁用高危权限

风险点FILE权限允许账号读取/写入服务器本地文件(如读取/etc/passwd、写入后门脚本),SUPER权限允许修改MySQL运行参数,非必要场景下需禁用。
操作步骤

  1. 查看账号是否拥有高危权限:
    mysql -uroot -p
    # 查看shop_app账号的权限
    show grants for 'shop_app'@'192.168.1.100';
    
  2. 回收高危权限(若存在):
    # 回收FILE权限
    revoke file on *.* from 'shop_app'@'192.168.1.100';
    # 回收SUPER权限(仅保留必要权限)
    revoke super on *.* from 'shop_app'@'192.168.1.100';
    flush privileges;
    
  3. 验证:确认账号无高危权限,执行select @@secure_file_priv;应返回/dev/null(禁止文件访问)。

2.4 防信息泄露:加密与审计双管齐下

即使账号和服务安全,若数据传输/存储未加密、操作无审计,仍可能导致敏感数据泄露且无法追溯:

(1)启用MySQL数据传输加密(SSL)

风险点:MySQL默认以明文传输数据,攻击者可通过抓包工具(如Wireshark)窃取传输中的账号密码、业务数据。
操作步骤

  1. 生成SSL证书(使用OpenSSL):
    # 创建证书存储目录
    mkdir -p /etc/mysql/ssl
    chown mysql:mysql /etc/mysql/ssl
    chmod 700 /etc/mysql/ssl
    # 生成CA证书、服务器证书和私钥
    openssl genrsa 2048 > /etc/mysql/ssl/ca-key.pem
    openssl req -new -x509 -nodes -days 3650 -key /etc/mysql/ssl/ca-key.pem > /etc/mysql/ssl/ca.pem
    openssl req -newkey rsa:2048 -days 3650 -nodes -keyout /etc/mysql/ssl/server-key.pem > /etc/mysql/ssl/server-req.pem
    openssl rsa -in /etc/mysql/ssl/server-key.pem -out /etc/mysql/ssl/server-key.pem
    openssl x509 -req -in /etc/mysql/ssl/server-req.pem -days 3650 -CA /etc/mysql/ssl/ca.pem -CAkey /etc/mysql/ssl/ca-key.pem -set_serial 01 > /etc/mysql/ssl/server-cert.pem
    
  2. 配置MySQL启用SSL:
    vi /etc/my.cnf
    # 添加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
    # 重启MySQL服务
    systemctl restart mysqld
    
  3. 验证:登录MySQL,确认SSL已启用:
    mysql -uroot -p
    show variables like '%ssl%';  # 应显示have_ssl=YES
    # 测试SSL连接
    mysql -ushop_app -p'ShopAppPass@2025' -h 192.168.1.50 --ssl-mode=REQUIRED
    
(2)敏感数据脱敏存储

风险点:数据库中存储的手机号、身份证号、银行卡号等敏感数据,若以明文存储,一旦数据库被入侵,将导致严重信息泄露。
操作步骤

  1. 对现有敏感字段进行脱敏(以手机号为例,保留前3位和后4位,中间用*代替):
    mysql -uroot -p
    # 假设ecommerce.user表的phone字段为明文手机号,修改为脱敏格式
    update ecommerce.user set phone = concat(left(phone,3), '****', right(phone,4)) where phone is not null;
    
  2. 新增数据时自动脱敏(通过触发器实现):
    # 创建触发器,插入数据时自动脱敏手机号
    delimiter //
    create trigger user_phone_desensitize before insert on ecommerce.user
    for each row
    begin
      set new.phone = concat(left(new.phone,3), '****', right(new.phone,4));
    end //
    delimiter ;
    
  3. 验证:插入一条新数据,确认手机号已脱敏:
    insert into ecommerce.user (name, phone) values ('张三', '13812345678');
    select name, phone from ecommerce.user where name='张三';  # 应显示138****5678
    
(3)开启MySQL审计日志

风险点:缺乏审计日志时,攻击者的操作(如删除数据、下载敏感表)无法追溯,难以定位攻击时间和范围。
操作步骤

  1. 配置MySQL开启通用查询日志(记录所有SQL操作,适合小规模环境;大规模环境建议使用专用审计工具如Percona Audit Log):
    vi /etc/my.cnf
    # 添加日志配置
    general_log = ON
    general_log_file = /var/log/mysql/general.log
    # 创建日志文件并设置权限
    touch /var/log/mysql/general.log
    chown mysql:mysql /var/log/mysql/general.log
    chmod 600 /var/log/mysql/general.log
    # 重启MySQL服务
    systemctl restart mysqld
    
  2. 验证:执行一条SQL操作,查看日志是否记录:
    mysql -ushop_app -p'ShopAppPass@2025' -e "select * from ecommerce.goods limit 1;"
    # 查看日志
    cat /var/log/mysql/general.log  # 应包含上述select操作的记录(时间、账号、SQL语句)
    

2.5 防拒绝服务:资源管控与性能优化

拒绝服务(DoS)攻击通过耗尽MySQL连接数、CPU/内存资源,导致数据库无法响应正常业务请求,需通过资源限制和查询优化防御:

(1)限制MySQL最大连接数

风险点:攻击者发起大量空连接或短连接,耗尽MySQL默认连接数(默认151),导致正常业务无法建立连接。
操作步骤

  1. 查看当前连接数配置和使用情况:
    mysql -uroot -p
    show variables like 'max_connections';  # 查看最大连接数
    show status like 'Threads_connected';  # 查看当前连接数
    
  2. 根据业务需求调整最大连接数(如设置为500,需结合服务器内存大小,避免连接过多导致内存不足):
    vi /etc/my.cnf
    # 添加最大连接数配置
    max_connections = 500
    # 设置等待超时时间(空闲连接超过10分钟自动关闭)
    wait_timeout = 600
    interactive_timeout = 600
    # 重启MySQL服务
    systemctl restart mysqld
    
  3. 验证:确认配置生效:
    show variables like 'max_connections';  # 应显示500
    
(2)优化慢查询,避免资源耗尽

风险点:未优化的复杂查询(如无索引的select *、多表关联无条件)会占用大量CPU和IO资源,导致数据库卡顿,甚至引发DoS。
操作步骤

  1. 开启慢查询日志,定位慢查询SQL:
    vi /etc/my.cnf
    # 开启慢查询日志
    slow_query_log = ON
    slow_query_log_file = /var/log/mysql/slow.log
    # 定义慢查询阈值(超过2秒的查询视为慢查询)
    long_query_time = 2
    # 记录未使用索引的查询(即使执行时间短,也可能存在风险)
    log_queries_not_using_indexes = ON
    # 重启MySQL服务
    systemctl restart mysqld
    
  2. 分析慢查询日志,优化SQL(以mysqldumpslow工具为例):
    # 查看慢查询日志中出现频率最高的10条SQL
    mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
    
  3. 优化示例:为无索引的字段添加索引(如ecommerce.goods表的category_id字段):
    mysql -uroot -p
    # 添加索引
    create index idx_goods_category on ecommerce.goods(category_id);
    
  4. 验证:再次执行原慢查询SQL,确认执行时间缩短至2秒以内。

三、加固效果验证与持续维护

MySQL安全加固不是一次性操作,需通过“效果验证+定期维护”确保长期安全:

3.1 加固效果验证清单

验证项目 验证方法 预期结果
账号安全 select user, host, password from mysql.user; 无test、stuff1账号,无匿名账号,dbuser1密码非弱口令
服务安全 nmap -p 3306 192.168.1.50(非授权IP) 3306端口不可达
权限安全 show grants for 'shop_app'@'192.168.1.100'; 仅含select、insert权限,无FILE、SUPER权限
加密安全 show variables like '%ssl%'; have_ssl=YES,连接需SSL
日志安全 cat /var/log/mysql/general.log 记录所有SQL操作,无缺失

3.2 持续维护建议

  1. 定期更新:每季度检查MySQL官方安全公告,及时升级修复新发现的漏洞;
  2. 权限审计:每月审计一次用户权限,回收废弃账号、过度授权的权限;
  3. 日志分析:每周查看慢查询日志和审计日志,定位异常操作(如批量删除数据、远程登录失败);
  4. 数据备份:每日自动备份数据库,定期测试备份恢复效果,防止数据丢失。

四、结语

MySQL数据库的安全加固核心在于“最小攻击面+最小权限+全链路防护”——从账号、服务、权限、数据到资源,每个环节都需针对性防御,同时结合持续的维护与审计,才能抵御不断演变的攻击手段。本文的实战方案基于CentOS 7环境,可根据实际操作系统(如Ubuntu、Windows Server)和MySQL版本调整细节,但核心原则(如弱口令清理、最小权限、加密传输)适用于所有MySQL部署场景。只有将安全加固融入日常运维,才能真正保障MySQL数据库的稳定与安全。

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐