解决DOS攻击生产案例:根据web日志或者或者网络连接数,监控当某个IP 并发连接数或者短时内PV达到100,即调用防火墙命令封掉对应的IP,监控频 率每隔5分钟。防火墙命令为:iptables -A INPUT -s IP -j REJECT
1 实验准备
1.1 攻击服务器环境准备
[root@localhost ~]# yum install hping3 -y
1.2 受攻击服务器环境准备
[13:42:52 root@centos8 ~]#yum install tcpdump httpd -y
[13:42:52 root@centos8 ~]#systemctl enable --now httpd
此时158上的80端口可以正常被访问.
2 实验开始
2.1 DOS攻击
对192.168.31.158进行
[14:10:14 root@centos8 ~]#hping3 -c 15000 -d 150 -S -w 64 -p 80 --flood 192.168.31.158
HPING 192.168.31.158 (ens33 192.168.31.158): S set, 40 headers + 150 data bytes
hping in flood mode, no replies will be shown
158上使用tcpdump可以看到大量来自157的请求
[root@localhost ~]# tcpdump src host 192.168.31.157
此时由于洪水攻击,造成网页无法访问
在158上可以看到有大量来自157的SYN-RECV连接
考虑到可能存在其他类型的攻击(比如ESTAB),就不用SYN-RECV进行过滤
2.2 获取IP信息
通过awk过滤后取到该列
ss -ano|awk '{print $6}'
再使用正则匹配到该列中的IP地址
ss -ano|awk '{print $6}'|grep -Eo "([0-9]{1,3}\.){3}[0-9]+"
再将这些ip进行排序
ss -ano|awk '{print $6}'|grep -Eo "([0-9]{1,3}\.){3}[0-9]+"|sort|uniq -c
最后再从多到少再次排序,这样获得了以下的结果
3 脚本编写
3.1 伪代码
1.监控当某个IP 并发连接数或者短时内PV达到100时
如果 某个IP的数量 -gt 100;那么执行
iptable 把对应的$IP加入到禁止访问列表中
否则 什么都不做.
2.代码每5分钟执行1次.用crontab实现
*/5 * * * * /data/scripts/flood_check.sh
3.2 伪代码进一步实现
3.2.1 取出与本机连接的IP并列出有多少个连接
ss -ano|awk '{print $6}'|grep -Eo "([0-9]{1,3}\.){3}[0-9]+"|sort|uniq -c|sort -r
3.2.2 按行取出每行内容
while read line
这样读出每行的内容为
100______192.168.31.157
数字______IP
3.2.3 判断IP出现的次数
再通过awk取到$1的数字部分,并对其进行判断
if [ `echo $line|awk '{print $1}'` -gt 10 ];then
3.2.4 拼接iptables规则
通过命令拼接实现了将大于10个连接的ip加入到iptables的input链并禁止访问
iptables -AINPUT -s `echo $line|awk '{print $2}'` -j REJECT;
3.3 半成品代码
#!/bin/bash
ss -ano|awk '{print $6}'|grep -Eo "([0-9]{1,3}\.){3}[0-9]+"|sort|uniq -c|sort -r |while read line;do
if [ `echo $line|awk '{print $1}'` -gt 10 ];then
iptables -AINPUT -s `echo $line|awk '{print $2}'` -j REJECT;
fi;
done
3.4 测试脚本
执行脚本前
执行脚本后
3.5 新问题
此时发现即便这个IP已经被禁止,由于禁止到完全断开需要一段时间,而此段时间内该IP会被重复添加,最终可能引起INPUT链过大不好管理
4 完善脚本
4.1 新增自定义链
iptables -N FLOOD_REJECT
判断iptables 有没有FLOOD_REJECT自定义证书链,如果没有则新建一个
iptables -L FLOOD_REJECT|grep -o FLOOD_REJECT &>/dev/null;[ $? -eq 0 ]|| iptables -N FLOOD_REJECT
判断是否将自定义证书链FLOOD_REJECT应用到INPUT链上,如果没有则关联
iptables -L INPUT|grep -o FLOOD_REJECT &>/dev/null;[ $? -eq 0 ]||iptables -IINPUT -j FLOOD_REJECT
将原来直接写入INPUT链的信息写入FLOOD_REJECT链
IP=`echo $line|awk '{print $2}'`
iptables -vnL FLOOD_REJECT|grep -o $IP &>/dev/null;[ $? -eq 0 ] || iptables -AFLOOD_REJECT -s $IP -j REJECT;
4.2 完善后的脚本
#!/bin/bash
iptables -L FLOOD_REJECT|grep -o FLOOD_REJECT &>/dev/null;[ $? -eq 0 ]|| iptables -N FLOOD_REJECT
iptables -L INPUT|grep -o FLOOD_REJECT &>/dev/null;[ $? -eq 0 ]||iptables -IINPUT -j FLOOD_REJECT
ss -ano|awk '{print $6}'|grep -Eo "([0-9]{1,3}\.){3}[0-9]+"|sort|uniq -c|sort -r |while read line;do
if [ `echo $line|awk '{print $1}'` -gt 10 ];then
IP=`echo $line|awk '{print $2}'`
iptables -vnL FLOOD_REJECT|grep -o $IP &>/dev/null;[ $? -eq 0 ] || iptables -AFLOOD_REJECT -s $IP -j REJECT;
fi;
done
现在不管短时间内脚本被执行几遍都不会再重复添加了
5 crontab添加
要求是每5分钟检查一次
[root@localhost ~]# crontab -e
*/5 * * * * /data/scripts/flood_check.sh