说实话,上周我帮一家做电商的小客户处理完事故,看着他们CEO那张苍白如纸的脸,真的挺不是滋味的。凌晨三点,监控报警说数据库CPU飙升到100%,等他们反应过来,已经有几万条用户数据被下载到了某个境外IP。那种无力感,我懂。很多中小企业主觉得“我的数据又不值钱,黑产懒得看我”,但真相是:在黑产眼里,你的客户手机号和订单记录,就是他们眼中的金矿。
今天这篇,我不讲那些虚头巴脑的理论,咱们直接上手,一步一步把你的MySQL从“裸奔”状态,变成连黑客都啃不动的硬骨头。如果你现在还在用 root/root 或者 admin/123456 这种密码登录生产库,请立刻、马上、现在就去改!
第一步:止血——如果你已经被拖库了
别慌,先确认现状。很多人发现异常后第一反应是重启服务,这是大错特错! 重启会清除内存中的攻击痕迹,让你无法追溯。
- 断网不断电:如果可能,拔掉网线或断开网络连接,但不要关闭MySQL进程。
- 保留现场:记录下当前的连接日志、慢查询日志、错误日志位置。
- 评估损失:查看最近7天的
general_log或slow_log,看看哪些表被大规模读取过。
-- 查看当前活跃连接,找出异常IP
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC;
-- 查看最近被大量访问的表(通过慢查询日志分析)
-- 假设慢查询日志路径为 /var/log/mysql/slow.log
-- 在Linux服务器上执行:
grep -E "SELECT|INSERT|UPDATE|DELETE" /var/log/mysql/slow.log | awk '{print $5}' | sort | uniq -c | sort -nr | head -20
记住,止血只是第一步,更重要的是别让它再次发生。
第二步:默认密码清零——改掉你的“裸奔”习惯
我见过太多人,装完MySQL连配置文件都没动,就用默认密码 root@localhost 跑在生产环境。这就像把家门钥匙挂在门外,还写着“免费自取”。
2.1 强制修改所有默认账户
-- 进入MySQL后,先列出所有用户
SELECT user, host FROM mysql.user;
-- 禁用或删除匿名账户
DROP USER ''@'localhost';
DROP USER ''@'%';
-- 修改root密码(使用强密码!)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'Str0ng!P@ssw0rd#2024';
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY 'Str0ng!P@ssw0rd#2024';
-- 创建专用应用账户,不要给应用root权限!
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'App#User$2024!';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'192.168.1.%';
FLUSH PRIVILEGES;
2.2 密码复杂度要求
中小企业最容易忽视的就是密码强度。一个12位的密码,包含大小写、数字、特殊字符,破解时间从“3分钟”变成“300年”。
-- 启用密码强度验证插件
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
-- 设置密码强度要求(示例:最小长度8,包含大小写数字特殊字符)
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 8;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.number_count = 1;
SET GLOBAL validate_password.special_char_count = 1;
第三步:最小权限原则——别给太多“特权”
很多开发者为了方便,给应用账户授予了 ALL PRIVILEGES,甚至 GRANT OPTION。这意味着一旦账户泄露,黑客就能创建新账户、删除表、甚至获取服务器权限。
3.1 只给必要的权限
-- 撤销root远程登录权限(生产环境严禁root远程登录)
DROP USER 'root'@'%';
DROP USER 'root'@'::1';
-- 为应用账户授予最小权限
-- 假设应用只需要读某几张表
GRANT SELECT ON mydb.orders TO 'app_user'@'192.168.1.%';
GRANT SELECT, INSERT ON mydb.user_profiles TO 'app_user'@'192.168.1.%';
GRANT SELECT ON mydb.products TO 'app_user'@'192.168.1.%';
-- 如果需要存储过程,单独授权
GRANT EXECUTE ON PROCEDURE mydb.sp_generate_report TO 'app_user'@'192.168.1.%';
-- 严禁授予以下权限(除非绝对必要)
-- FILE (可以读取服务器文件)
-- SUPER (可以管理其他连接)
-- PROCESS (可以看到所有SQL语句)
-- SHUTDOWN (可以关闭数据库)
3.2 定期审计权限
每季度跑一次这个脚本,清理无用权限:
-- 找出长期未使用的账户
SELECT user, host, created, last_login
FROM mysql.user
WHERE last_login < DATE_SUB(NOW(), INTERVAL 90 DAY)
AND user NOT IN ('mysql.sys', 'mysql.infoschema');
-- 找出拥有FILE权限的危险账户
SELECT user, host FROM mysql.user
WHERE File_priv = 'Y';
第四步:防火墙白名单——把门装上电子锁
即使MySQL配置再完美,如果端口对全世界开放,风险依然存在。中小企业最常用的云服务商(阿里云、腾讯云、AWS等)都提供安全组功能,务必只允许应用服务器IP访问数据库端口(默认3306)。
4.1 云服务商安全组配置
以阿里云为例:
- 入站规则:只允许Web服务器安全组的IP段访问TCP 3306端口
- 出站规则:通常无需限制,但建议禁止MySQL服务器主动外连
4.2 服务器内部iptables规则
如果你们有自己的物理机或VM,用iptables做第二道防线:
# 仅允许192.168.1.0/24网段访问3306端口
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 3306 -j ACCEPT
# 拒绝其他所有IP访问3306
iptables -A INPUT -p tcp --dport 3306 -j DROP
# 保存规则(CentOS 7+)
iptables-save > /etc/sysconfig/iptables
4.3 MySQL绑定地址配置
修改MySQL配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf(Ubuntu/Debian)或 /etc/my.cnf(CentOS):
[mysqld]
# 只绑定内网IP,不暴露公网
bind-address = 192.168.1.100
# 或者干脆不绑定,让防火墙说了算(推荐)
# bind-address = 0.0.0.0
重启MySQL生效:
systemctl restart mysql
第五步:加密传输——别让数据在网线上裸奔
默认情况下,MySQL数据传输是明文的。黑客只要在你的网络链路中“窃听”,就能拿到所有SQL语句和密码。
5.1 启用SSL连接
-- 检查SSL是否启用
SHOW VARIABLES LIKE '%ssl%';
-- 如果未启用,需要生成证书并配置
-- 使用MySQL自带的脚本生成证书(MySQL 5.7+)
mysqld --initialize-insecure
mysqld_ssl_rsa_setup --datadir=/var/lib/mysql
-- 修改my.cnf
[mysqld]
ssl-ca=/var/lib/mysql/ca.pem
ssl-cert=/var/lib/mysql/server-cert.pem
ssl-key=/var/lib/mysql/server-key.pem
-- 强制要求客户端使用SSL
ALTER USER 'app_user'@'192.168.1.%' REQUIRE SSL;
5.2 应用程序端配置
在代码中(以Python为例):
import pymysql
connection = pymysql.connect(
host='192.168.1.100',
user='app_user',
password='App#User$2024!',
database='mydb',
ssl_ca='/path/to/ca.pem',
ssl_verify_cert=True,
ssl_verify_identity=True
)
第六步:日志监控——装个“监控摄像头”
很多中小企业没有专门的DBA,但这不代表不能做日志监控。开启通用日志和慢查询日志,配合简单的脚本报警,就能发现大部分异常。
6.1 开启必要日志
[mysqld]
# 错误日志(默认开启)
log_error=/var/log/mysql/error.log
# 慢查询日志(阈值设为1秒)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
# 通用日志(生产环境谨慎开启,性能有影响,建议按需开启)
# general_log = 1
# general_log_file = /var/log/mysql/general.log
6.2 简单的异常检测脚本
#!/bin/bash
# check_mysql_anomaly.sh - 每5分钟运行一次
LOG_FILE="/var/log/mysql/slow.log"
ALERT_EMAIL="admin@yourcompany.com"
# 检查最近5分钟是否有大量慢查询
COUNT=$(grep -c "$(date -d '5 minutes ago' '+%y%m%d %H:%M:%S')" "$LOG_FILE" 2>/dev/null || echo 0)
# 如果超过10条慢查询,发送告警
if [ "$COUNT" -gt 10 ]; then
echo "Alert: $COUNT slow queries detected in last 5 minutes" | mail -s "MySQL Slow Query Alert" "$ALERT_EMAIL"
fi
# 检查错误日志中是否有拒绝连接的记录
REJECTED=$(grep -c "Access denied" /var/log/mysql/error.log | tail -1)
if [ "$REJECTED" -gt 5 ]; then
echo "Alert: Multiple access denied errors detected" | mail -s "MySQL Access Alert" "$ALERT_EMAIL"
fi
把这个脚本加到crontab:
*/5 * * * * /root/check_mysql_anomaly.sh
第七步:定期备份——最后的救命稻草
再好的防护也可能出问题。备份不是为了恢复数据,而是为了在数据被删光时还能翻盘。
7.1 自动化备份脚本
#!/bin/bash
# backup_mysql.sh
BACKUP_DIR="/backup/mysql"
DATE=$(date '+%Y%m%d_%H%M%S')
DB_USER="root"
DB_PASS="Str0ng!P@ssw0rd#2024"
DB_NAME="mydb"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份数据库
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.sql
# 压缩备份
gzip $BACKUP_DIR/${DB_NAME}_${DATE}.sql
# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
# 上传到对象存储(以阿里云OSS为例)
ossutil cp $BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz oss://your-bucket/mysql-backup/
7.2 恢复演练
备份了不恢复,等于没备份。每季度做一次恢复演练,确保备份文件可用。
# 测试恢复(在测试环境执行)
gunzip < /backup/mysql/mydb_20240101_120000.sql.gz | mysql -u root -p test_db
第八步:补丁管理——别让已知漏洞成为突破口
MySQL官方会定期发布安全补丁。很多中小企业数据库几年不升级,停留在5.6甚至5.5版本,这些版本存在大量已知漏洞。
# 检查当前MySQL版本
mysql -V
# 查看是否有安全更新(以CentOS为例)
yum check-update | grep mysql
# 升级到最新安全版本
yum update mysql-server -y
systemctl restart mysql
结语:安全是一个持续的过程
写到这里,你可能觉得步骤很多。但相信我,花2小时做好这些配置,能帮你避免损失几十万的潜在风险。安全不是一次性的任务,而是日常习惯。
最后送你一句话:“不要让你的数据库,成为黑客送你的新年礼物。” 如果你现在还在用默认密码,或者端口对公网开放,立刻去改!
有问题?欢迎在评论区留言,我会尽力帮你解答。别忘了点赞收藏,转发给你公司的IT负责人看!
