在 Ubuntu 公网主机上配置 Fail2ban 防止 SSH 暴力破解攻击
背景
今天在SakuraFrp内网穿透平台上签到时,发现近几天一直存在少量流量偷跑。我在SakuraFrp上只部署了到主机SSH的内网穿透,因此怀疑有人在使用暴力方法破解SSH密码。
在Shell中执行以下指令,可以看到近期尝试登录失败的记录:
sudo cat /var/log/auth.log | grep "Failed"
返回结果如下(部分):
可以看到确实有主机在尝试破解SSH密码,在图中就可以看到的有72.5.*.*,45.145.*.*,139.59.*.*,79.6.*.*四台主机在尝试破解SSH密码,可以预见的是攻击方要么有一个由数台主机组成的僵尸网络,要么利用了数个代理服务器进行本次攻击。
虽然主机并不支持SSH直接登录root用户,也不存在过于简单的用户名,更不存在弱密码用户,理论上像这样用户名取字典的破解手段对主机无效,但是这就好比有人一直在敲你家门,虽然你可以不开门,但是心里肯定不踏实。于是我就想到能不能使用一些手段,当某IP连续登录SSH失败次数过多时,将该IP封建,直接拒绝其访问主机。经过查找相关资料,发现Fail2ban可以实现此功能。
正文
在Ubuntu上使用如下指令可以安装Fail2ban。
sudo apt-get install fail2ban
安装完成后需要配置Fail2ban以何种方式监听登录失败信息,Fail2ban的工作模式是检查登录日志,换言之,它也是通过跟踪 /var/log/auth.log
的内容来决定哪些IP需要被封禁的。
Fail2ban的配置文件在 /etc/fail2ban/jail.conf
,但是这个文件在Fail2ban每次更新后都会被重写,所以不建议使用。推荐创建新文件 /etc/fail2ban/jail.local
写入相关配置,该文件Fail2ban也会读取,且不会将其重写。
使用nano创建配置文件并打开(当然你也可以复制一份 jail.conf
):
sudo nano /etc/fail2ban/jail.local
在其中写入如下配置:
[sshd]
enabled = true # 是否启用规则
findtime = 3600 # 计时器重置时间
maxretry = 3 # 最大尝试次数
bantime = 10800 # 单次封建时间
filter = sshd # SSH登录日志文件解析配置
logpath = /var/log/auth.log # SSH登录日志文件位置
action = ufw[application="OpenSSH", blocktype=reject] # 封禁时执行的操作
[sshd]
只是一个标签,其中 sshd
可以被替换为任何字符串,enable
表示启用此规则,findtime
表示重置失败计数器的时间间隔,单位为秒,maxretry
表示在 findtime
时间内,最多重试次数,一旦重试超过该此次数,就会触发规则封建IP,bantime
表示一旦触发规则,该IP将会被封建多长时间,单位为秒。在上述配置中,一旦某IP在一小时内连续三次尝试登录失败,就会被封建IP三小时,在此期间该IP如果想再次登录SSH,会直接被拒绝。
接下来三项比较重要,filter
表示参考哪个配置文件来解读日志文件 /var/log/auth.log
,此处选择的配置文件为 /etc/fail2ban/filter.d/sshd.conf
。logpath
是配置文件的所在位置。action
表示当触发封禁条件时,如何封禁该IP,没有这一项将会导致Fail2ban无法正常工作,请注意中文论坛上大部分关于配置Fail2ban的教程都没有写出这一项配置,此处表示使用 ufw
防火墙拒绝相关访问请求,因此要让Fail2ban正常工作必须保证 ufw
正在运行,ufw
拒绝访问条件是访问的应用为OpenSSH,阻止的方式为reject。如果你使用 iptables
,也可以将此项替换为类似下面这种写法。
action = iptables[name=SSH, port=ssh, protocol=tcp]
之后使用如下指令重启Fail2ban即可让Fail2ban读取新的配置文件。
sudo service fail2ban restart
可以用如下指令检查Fail2ban是否正常执行。
sudo service fail2ban status
看到绿色的active (running)
表示服务成功运行。
用以下指令可以看到fail2ban启用的规则和每个规则当前正被封建的IP。
sudo fail2ban-client status
sudo fail2ban-client status sshd
直接查看 ufw
配置信息也可以看到被封禁的IP。
sudo ufw status numbered
结果:
可以看到79.6.*.*和139.59.*.*已经被封禁了。
使用自定义封禁规则
Fail2ban默认的ufw规则关闭SSH端口所采取的策略是关闭SSH的默认端口22号端口(根本上是因为ufw也是这么工作的),如果SSH服务并不在22号端口上,或者想使用Fail2ban对其它服务的端口进行管理,则需要自己编写封禁规则。下面以SSH服务在2222号端口上为例演示如何编写自己的封禁规则。
使用 nano
创建文件 ufw-ssh.conf
,用来告诉Fail2ban如何使用 ufw
阻止SSH请求:
sudo nano /etc/fail2ban/action.d/ufw-ssh.conf
在其中写入:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = ufw insert 1 reject from <ip> to any port <port>
actionunban = ufw delete reject from <ip> to any port <port>
可以看到有关操作的值就是当想要执行此操作时,需要执行的shell指令,其中 <port>
表示可选参数,会在 jail.local
中给出。
需要注意的是,ufw
对过滤条件的顺序有要求,要正确阻止指定IP访问SSH,必须保证该规则位于打开SSH端口的规则之前,因此此处使用 insert 1
将新规则插入 ufw
配置的第一行,不应该直接使用 reject
将规则放在原规则的末尾。
除了使用 reject
规则,还可以使用 deny
规则,区别是ufw会主动拒绝被 reject
规则命中的连接,被 deny
规则命中的连接不会被主动拒绝,而是不做出回应直到连接超时。
最后在 jail.local
中将 action
字段替换为自己的配置。
action = ufw-ssh[port=2222]
如果想使用Fail2ban管理不常见服务的连接,还有可能需要自行编写对日志的匹配规则,这部分规则储存在 /etc/fail2ban/filter.d/
中。笔者还未研究过此类规则的编写方法,因此不在这里介绍。
结语
Fail2ban只能阻止攻击来源IP固定的暴力破解攻击,面对僵尸网络和攻击方具有较多代理服务器的攻击比较乏力。相比使用IP封建等手段检测非法IP并予以回击的反击手段,更合适的应对方式是做好SSH暴力攻击的预防手段。比如
- 禁止使用SSH登录root账户。
- 不取过于简单的用户名和字典可破的用户名(如
pi
,admin
)。 - 不使用过于简单的密码(少于8位)和字典可破的密码。
- 保证主机上的其余账户(即使并非sudo账户)都满足如上2、3规则。
- 非必要不泄露主机的域名和IP地址(不过大多数情况下域名就是为了让其它人访问的)。
- 非必要不泄露主机的主机名和主机上已存在账户的用户名。
- 非必要不要内网穿透SSH,如果有必要,尽量使用内网穿透平台提供的额外安全手段。
- 非必要不使用SSH的默认端口22,如果你的主机位于运营商统一提供的IP连续的公网,或者使用了内网穿透,攻击者可以用nmap直接对整个子网上的主机进行嗅探,很容易就会发现那些开放了22端口的靶机。将SSH所在的端口移至其它不常有服务使用的偏僻端口能够很大程度上降低被攻击的可能。
最后,祝大家的主机都能安全,不会遭遇到各种手段的攻击。