Shell脚本防止Linux远程SSH暴力破解
概述:
在CentOS云服务器上使用“journalctl”工具发现系统上存在大量的SSHD日志,大概意思是一直有来自不同国家和地区的IP地址、更换各种不同用户名和端口的暴力连接尝试:
执行命令:
journalctl --since "开始时间" --until "结束时间"
日志内容:
pam_unix(sshd:auth): check pass; user unknown
pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=IP地址
Failed password for invalid user 用户名 from IP地址 port 端口号 ssh2
Received disconnect from IP地址 port 端口号:11: Bye Bye [preauth]
Disconnected from invalid user 用户名 IP地址 port 端口号 [preauth]
由于防火墙没有配置仅开放特定的端口和源地址,单纯的禁止root远程登录或修改默认端口,虽然能有效的防止尝试成功,但是总是被访问也很烦人。
虽然访问量不是特别大,但是在某些情况下,特别是服务器负载非常高的时候,也会形成被DDOS的效果,例如在某些服务构建了大量的磁盘IO的时候,可能出现了和sssd_nss争抢CPU资源的情况,然后nss被watchdog干掉,然后服务器卡死。
P.S. 上面这段是瞎猜的,可以略过。系统为什么死了不太清除,云服务器控制台显示磁盘IO繁忙100%了,可能是其他服务导致的,因为之前sssd_nss也被watchdog干掉过几次,都没出现问题。
Child [442357] ('nss':'nss') was terminated by own WATCHDOG. Consult corresponding logs to figure out the reason.
正文:
创建路径和拒绝IP列表的文件
mkdir sshPrevent
cd sshPrevent
touch ipblack.list
创建shell脚本
vim sshPrevent.sh
编辑脚本内容
#! /bin/bash
# 获取近期访问系统失败的IP地址和失败次数
# cat /var/log/secure|awk '/Failed/{print $(NF-3)}'|sort|uniq -c|awk '{print $2"="$1;}' > /sshPrevent/ipblack.list
# awk '/Connection closed.*preauth/ && !/user/ {ip=$(NF-3); print ip} /Failed/ {ip=$(NF-3); print ip}' /var/log/secure | sort | uniq -c | awk '{print $2"="$1;}' > /sshPrevent/ipblack.list
awk '/Connection closed.*preauth/ && !/user/ {
match($0, /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/);
if (RSTART > 0) {
print substr($0, RSTART, RLENGTH);
}
} /Failed/ {
match($0, /([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/);
if (RSTART > 0) {
print substr($0, RSTART, RLENGTH);
}
}' /var/log/secure | sort | uniq -c | awk '{print $2"="$1;}' > /sshPrevent/ipblack.list
# 设置阈值
define="5"
# 对列表中的IP地址进行处理
for i in `cat /sshPrevent/ipblack.list`
do
ip=`echo $i |awk -F= '{print $1}'`
num=`echo $i|awk -F= '{print $2}'`
# 判断访问失败次数,超过允许次数则加入黑名单
if [ $num -gt $define ];then
# 确认该IP地址是否已经在黑名单中
var1=$(firewall-cmd --list-all |grep $ip)
# 如果不在黑名单中则执行以下操作
if [[ -z $var1 ]];then
# firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="$ip" reject'
# 新增到firewall reject
var2=$(firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address=$ip reject" 2>&1)
# 重新加载firewall
var3=$(firewall-cmd --reload 2>&1)
fi
fi
done
修改shell执行权限
chmod +x sshPrevent.sh
确认firewall服务处于开启状态
systemctl status firewalld
执行shell脚本
./sshPrevent.sh
检查firewall策略
firewall-cmd --list-all
设置定时任务(整点执行)
crontab -e
总结
1、创建一个工作目录“/sshPrevent”,记录ip黑名单的列表“ipblack.list”,执行任务的脚本“sshPrevent.sh”。
2、从安全日志“/var/log/secure”中读取访问失败的用户的IP地址,并连同失败次数记录到“ipblack.list”(覆盖原记录即可,因为原记录已经处理过了)。
3、从“ipblack.list”中循环读取ip地址和失败次数,判断次数是否超过阈值,超过则添加到“firewall”(CentOS8默认没有host.deny和iptables,所以用firewall)。
4、判当前IP是否已经在“firewall”中,已经存在则不处理,如果不在则添加规则拒绝访问,然后重新加载firewall规则。
5、测试完成后配置到定时任务,每小时或每天执行即可。
6、当然,如果服务器如果可以设置成仅允许特定的端口和远端IP可以访问,其他全部拒绝,就不用这么麻烦了。
yunxi p.deng 2024/06/22