本人的博客系统和 MySQL是阿里云服务器自建的,没有使用第三方云数据库,之前在排查 MySQL 错误的时候,查阅了错误日志,这不查不知道,一查吓一跳。我去,错误日志里面全部都是别人在试 MySQL 的账号密码。
我顿时惊出了一身冷汗,这要是被别人黑进数据库那还得了。赶紧去网上找解决方案,对比了很多方案,最终选择了 fail2ban
介绍
fail2ban
是一个用 Python 编写的轻量级开源入侵防御软件框架,主要用于防止暴力破解攻击。它通过监控日志文件中的失败登录尝试、可疑活动或其他特定事件,自动更新防火墙规则以阻止这些恶意活动的 IP 地址,它的资源占用非常低,适合在大多数服务器和网络设备上运行。
官网地址(基本没啥介绍,不如看这篇博客)
安装和使用
1. 安装 fail2ban
在你的服务器上安装 fail2ban
:
sudo apt-get update
sudo apt-get install fail2ban
2. 配置 MySQL 日志
首先,确保 MySQL 的错误日志记录已启用。编辑 MySQL 的配置文件(通常是 /etc/mysql/my.cnf
或 /etc/mysql/mysql.conf.d/mysqld.cnf
),确保以下行存在且未被注释:
[mysqld]
log_error = /var/log/mysql/error.log
重启 MySQL 服务以应用更改:
sudo systemctl restart mysql
3. 创建 fail2ban
过滤器
创建一个新的过滤器文件,用于检测 MySQL 登录失败的日志。该文件应放在 /etc/fail2ban/filter.d/mysql-auth.conf
:
sudo vim /etc/fail2ban/filter.d/mysql-auth.conf
在文件中添加以下内容:
[Definition]
failregex = ^.*Access denied for user '.*'@'<HOST>' .*$
4. 配置 fail2ban jail
编辑 fail2ban
的配置文件 /etc/fail2ban/jail.local
,添加一个新的 jail 来处理 MySQL 登录失败的情况:
sudo vim /etc/fail2ban/jail.local
在文件中添加以下内容:
[mysqld-auth]
enabled = true
filter = mysql-auth
action = iptables-multiport[name=MySQL, port="3306", protocol=tcp]
logpath = /var/log/mysql/error.log
maxretry = 3
bantime = 3600
5. 重启 fail2ban 服务
重启 Fail2ban 以应用新的配置:
sudo systemctl restart fail2ban
6. 验证配置
可以通过以下命令检查 fail2ban 的状态,确保配置生效:
sudo fail2ban-client status mysqld-auth
配置介绍
fail2ban
核心的配置文件是jail.local
,里面包含封禁规则、邮件通知等配置。每个 jail 可以覆盖默认设置,使用自己的 filter、logpath、maxretry 等参数。
# 这个部分定义了所有 jail 的默认设置
[DEFAULT]
# 指定不会被封禁的 IP 地址或网段。
ignoreip = 127.0.0.1/8 ::1
# 封禁时间,默认为 10 分钟。可以使用 s(秒),m(分),h(小时),d(天)。
bantime = 10m
# 在这个时间窗口内寻找匹配的失败次数
findtime = 10m
# 在 findtime 内允许的最大失败次数。
maxretry = 5
# 日志文件监控后端(auto, pyinotify, gamin, polling)。
backend = auto
# 操作模式(normal, ddos, extra 或 aggressive)。
mode = normal
# 默认协议。
protocol = tcp
# iptables 链名。
chain = INPUT
# 动作相关参数:
# 定义封禁 IP 的方法,默认使用 iptables。
banaction = iptables-multiport
# 封禁所有端口的动作。
banaction_allports = iptables-allports
# 定义检测到攻击时要执行的动作。
action = %(action_)s
# 邮件通知相关:
# 接收通知的邮箱地址。
destemail = root@localhost
# 发送通知的邮箱地址。
sender = root@<fq-hostname>
# 用于发送邮件的邮件传输代理。
mta = sendmail
# 日志相关:
# 日志级别,可选值有 CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG。
loglevel = INFO
# 日志文件的位置。
logtarget = /var/log/fail2ban.log
# 日志文件编码。
logencoding = auto
# 具体服务的 jail 配置:
# [sshd] 部分示例:
[sshd]
# 是否启用该 jail。
enabled = true
# 监控的端口。
port = ssh
# 使用的过滤器名称
filter = sshd
# 要监控的日志文件路径。
logpath = %(sshd_log)s
# 使用的后端。
backend = %(sshd_backend)s
# 高级配置:
# 是否使用 DNS 反向查找(yes, warn, no)。
usedns = warn
# 定义用于检测失败尝试的正则表达式。
failregex = ^%(__prefix_line)s(?:(?:Authentication failure|Failed [-/\w+]+) for(?: iI user)?|Ii user|ROOT LOGIN REFUSED) .*(?: from|FROM) <HOST>
# 定义要忽略的模式的正则表达式。
ignoreregex =
# 数据库清理年龄。
dbpurgeage = 1d
# 每个 IP 的最大匹配数。
dbmaxmatches = 10
# 启用递增封禁时间。
bantime.increment = true
# 封禁时间递增因子。
bantime.factor = 1
# 封禁时间计算公式。
bantime.formula = ban.Time * math.exp(float(ban.Count+1)banFactor)/math.exp(1banFactor)
# 封禁时间乘数序列。
bantime.multipliers = 1 5 30 60 300 720 1440 2880
# 是否跨 jail 累积封禁时间。
bantime.overalljails = false
常用命令
- 查看
fail2ban
状态
sudo fail2ban-client status
- 查看特定监狱(
jail
)的状态
sudo fail2ban-client status <监狱名>
- 启动
fail2ban
服务
sudo systemctl start fail2ban
- 停止
fail2ban
服务
sudo systemctl stop fail2ban
- 重启
fail2ban
服务
sudo systemctl restart fail2ban
- 手动封禁IP
sudo fail2ban-client set <监狱名> banip <IP地址>
- 手动解封IP
sudo fail2ban-client set <监狱名> unbanip <IP地址>
- 查看
fail2ban
日志
sudo tail -f /var/log/fail2ban.log
- 重新加载配置文件
sudo fail2ban-client reload
- 查看
fail2ban
版本
fail2ban-client version
Docker Compose
- 目录结构
fail2ban
├── docker-compose.yml
├── filter.d
│ └── mysql-auth.conf
└── jail.local
docker-compose.yml
version: '3'
services:
fail2ban:
container_name: fail2ban
image: crazymax/fail2ban:latest
platform: linux/amd64
volumes:
- ./jail.local:/etc/fail2ban/jail.local
- ./filter.d:/etc/fail2ban/filter.d
- /path/to/mysql/error.log:/var/log/mysql/error.log # 更换为实际的 mysql 错误日志路径
cap_add:
- NET_ADMIN
- NET_RAW
environment:
TZ: Asia/Shanghai
privileged: true
network_mode: host
restart: always
command: [ "fail2ban-server", "-f", "-x", "-v", "start" ]
mysql-auth.conf
[Definition]
failregex = Access denied for user '.*?'@'<HOST>'.*?
ignoreregex =
jail.local
[mysql-auth]
enabled = true
filter = mysql-auth
logpath = /var/log/mysql/error.log
maxretry = 3
bantime = 10m
findtime = 10m
chain = DOCKER-USER
port = 3306
jail
的filter
参数值必须是过滤器的文件名,例如filter = mysql-auth
,那么在filter.d
文件夹下必须有一个名为mysql-auth.conf
的文件,否则会导致不起作用或者报错
cd
到当前目录,然后用docker-compose up -d
部署就行了
其他服务的保护
fail2ban
不仅可以保护 MySQL 服务,还可以配置用于保护其他服务,如SSH、 Apache、Nginx、FTP 等,只需要配置好对应的jail
就行了。
其他常见 jail
:
[selinux-ssh]
[dropin-custom]
[pam-generic]
[xinetd-fail]
[recidive]
[nginx-http-auth]
[nginx-botsearch]
[nginx-badbots]
[apache-auth]
[apache-badbots]
[apache-noscript]
[apache-overflows]
[postfix]
[postfix-rbl]
[sendmail-auth]
[sendmail-reject]
[dovecot]
[sieve]
[mysqld-auth]