【提示:】本文主要介绍 UFW 相关的内容,不考虑 fail2ban,fail2ban 是一个很好的对付恶意访问的工具,但是不在本文讨论之列。

前面说了《使用 IP 地址列表(如黑名单、白名单)来批量添加 UFW 规则》,那么 IP 地址列表从何而来呢?从日志中。

如果不小心暴漏了服务器的真实 IP 地址,我们的服务器可能每天都要受到很多恶意 IP 的扫描,如果开启了日志,我们可以从日志中看到,例如下图是截取的部分 nginx 日志,我们能看到很短的时间内来了一大串恶意扫描(IP 地址部分在后面,没有截上)。

nginx 恶意扫描日志截图

我们要做的就是获取日志中的恶意 IP,然后进行整理并添加到 UFW 规则里。怎么整理呢?我用的是 AWK,AWK 是一个非常强悍的工具,关于 AWK 的各类实用功能可以自行搜索,本文不做介绍。

我们把获取、整理、添加等这一连串的命令写到一个 .sh 文件里,最后在 crontab 里添加自动任务,每隔一段时间调用 bash 运行一下这个脚本就可以了。

首先,要获取 IP 地址,这个可以用 cat、awk、sort 组合来实现,具体如下:

cat /var/log/nginx/host.access.log | awk '{print $1}' | sort -u >> ip2ban.txt

注意,我的日志文件里 IP 地址就在第一列,所以是 $1,这个要具体情况具体对待。并且,我选取的是直接访问服务器 IP 的日志,所以可以默认的把来源 IP 全部当成恶意 IP,不需要再额外整理,这样简单一些。

接下来,再运行一个组合命令,来添加规则,这个前文已经介绍过了,不要忘了 insert 1,否则规则可能被之前已经存在的允许规则所盖住。

while read line; do sudo ufw insert 1 deny from $line; done < /path/to/ip2ban.txt

上面这两个命令基本上就是雏形了,我们把它们结合到一块儿:

cat /var/log/nginx/host.access.log | awk '{print $1}' | sort -u >> ip2ban.txt | while read line; do sudo ufw insert 1 deny from $line; done < ip2ban.txt

哈哈,这样子是不行的,pipe 又不是 &&,| 竖杠用多了,随手就打上了,都忘了它的具体含义了,pipe 是把前一个的输出做为后一个的输入,而在这里,并不是这种情况,所以,要用 && 来连接。

cat /var/log/nginx/host.access.log | awk '{print $1}' | sort -u >> ip2ban.txt && while read line; do sudo ufw insert 1 deny from $line; done < ip2ban.txt

然后,清理一下日志文件,以便重新记录,免得日志太大,重复的太多。清空日志可以用下面的命令:

sudo bash -c '>/var/log/nginx/host.access.log'

当然,三组命令,可以全部合到一块儿,如下:

cat /var/log/nginx/host.access.log | awk '{print $1}' | sort -u >> ip2ban.txt && while read line; do sudo ufw insert 1 deny from $line; done < ip2ban.txt && sudo bash -c '>/var/log/nginx/host.access.log'

然后,把这一长串命令放到一个 .sh 文件里,这样每次只需要运行这个 .sh 文件就可以了。

#!/bin/bash
cd ~ && cat /var/log/nginx/host.access.log | awk '{print $1}' | sort -u >> ip2ban.txt && while read line; do sudo ufw insert 1 deny from $line; done < ip2ban.txt && sudo bash -c '>/var/log/nginx/host.access.log'

比如把上面保存为 ip2ban.sh,那么每次只需要 bash ip2ban.sh 就可以了。

再然后,部署自动化,把这项命令加到 crontab 里,设置间隔多长时间执行一次,这样就交由系统自动来运行了。

crontab -e

运行上面命令,调出编辑框,然后在 crontab file 下面加上要在指定时间运行的命令,时间格式为: minute (m), hour (h), day of month (dom), month (mon), and day of week (dow) or use ‘*’ in these fields (for ‘any’).

#
# m h  dom mon dow   command
#
0 */3 * * * bash /home/sudonext/dotsh/ipban.sh

比如上面的命令即:每三小时(前面的 0 是指第 0 分钟,也就是每隔三个小时的整点)执行一次 bash /home/sudonext/dotsh/ipban.sh

【注意:】执行的命令文件,最好用绝对地址,直观明了,相对地址容易写错。

【备注:】为什么不用 fail2ban?因为我觉得 fail2ban 配置起来太麻烦,也不想在额外安装这么个软件。下面也是类似,为什么要用 sort?因为我要用 sort -u 来排除重复项,那为什么不直接用 AWK?AWK 也可以做到啊,但是我一看 AWK 命令那写法,类似下面这样的,使用正则:

awk '!NF || !seen[$0]++'

对我这种智商的人来说,正则表达式有点太复杂了,我知道正则超级强大,但是还是能避免就避免,还是 sort -u 好记。

好了,基本上就是这样了,对于一个很懒又不想记复杂的命令的人来说,这样基本上也算是一种实现自动化的方式了。