根据nginx日志自动封禁 IP
遇到的问题问题:
攻击者会每秒 POST 请求 /a/b.php 数次,拉黑后过一段时间会切到其他 IP 继续攻击,如果开始攻击大概 100 行内就可以找到这种日志,需要检测这种信息,几分钟执行一次并去拉黑
Tips:如果是大规模 ddos 或 cc 攻击的话,这是不顶用的,还是需要上 高防IP 或者 CDN 或者 高防流量包 以及 添加防火墙进行流量清洗 等。
思路一: iptables
- 编写脚本,按日期拆分access.log
- 编写定时任务,每天0点拆分访问日志
- 编写脚本,分析access.log访问日志,封禁当天访问次数超过200的ip
- 编写定时任务,每10分钟执行一次封禁ip脚本
这样做的比较好的一点是,让小黑子连 403 也看不到,高效简单
日志拆分脚本
LOG_PATH
和 PID
换成你自己的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| # 每天0点执行日志按日期分隔脚本 0 0 * * * cd /www/Home/ && ./log_cut.sh #!/bin/bash #此脚本⽤于⾃动分割Nginx的⽇志,包括access.log #每天00:00执⾏此脚本将前⼀天的access.log重命名为access-xxxx-xx-xx.log格式,并重新打开⽇志⽂件 #Nginx⽇志⽂件所在⽬录 todo 换成你自己的 LOG_PATH=/data/logs/nginx/
#获取昨天的⽇期 YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
#获取pid⽂件路径 todo 换成你自己的 PID=/var/run/nginx.pid
#分割⽇志 mv ${LOG_PATH}access.log ${LOG_PATH}access-${YESTERDAY}.log
#向Nginx主进程发送USR1信号,重新打开⽇志⽂件 kill -USR1 `cat ${PID}`
|
编写定时任务
1 2 3 4
| crontab -e
# 每天0点执行日志按日期分隔脚本 0 0 * * * cd /www/Home/ && ./log_cut.sh
|
编写封禁ip脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 每十分钟执行一次封禁ip脚本 */10 * * * * cd /www/Home/ && ./blackip.sh #!/bin/bash logdir=/data/logs/nginx/access.log #nginx访问日志文件路径 port=443 #循环遍历日志文件取出访问量大于100的ip(忽略自己本地ip) for drop_ip in $(cat $logdir | grep -v '127.0.0.1' | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if ($1>100) print $2}'); do # 避免重复添加 num=$(grep ${drop_ip} /tmp/nginx_deny.log | wc -l) if [ $num -ge 1 ]; then continue fi # shellcheck disable=SC2154 iptables -I INPUT -p tcp --dport ${port} -s ${drop_ip} -j DROP echo ">>>>> $(date '+%Y-%m-%d %H%M%S') - 发现攻击源地址 -> ${drop_ip} " >>/tmp/nginx_deny.log #记录log done
|
编写封禁ip定时任务
1 2 3 4
| crontab -e
# 每十分钟执行一次封禁ip脚本 */10 * * * * cd /www/Home/ && ./blackip.sh
|
误封IP后 解封 IP
1 2 3 4 5
| #清空屏蔽IP iptables -t filter -D INPUT -s 1.2.3.4 -j DROP
#一键清空所有规则 iptables -F
|
思路二:nginx
配置nginx的黑名单,每次填加新的黑名单之后,但还要 重载/重启Nginx。 还有一点,会让小黑子看到 403 ,所以这不一定是最优解,大概思路如下:
定时查看 access.log 日志,将这些有问题的 IP 加入黑名单
编写 sh 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #!/bin/bash max=500 #我们设定的最大值,当访问量大于这个值得时候,封锁 confdir=/usr/local/data/nginx/conf/blockip.conf #nginx封锁配置文件路径 logdir=/usr/local/data/nginx/logs/access_huke88.log #nginx访问日志文件路径 #检测文件 test -e ${confdir} || touch ${confdir} drop_ip="" #循环遍历日志文件取出访问量大于500的ip for drop_ip in $(cat $logdir | awk '{print $1}' | sort | uniq -c | sort -rn | awk '{if ($1>500) print $2}') do grep -q "${drop_Ip}" ${confdir} && eg=1 || eg=0; if (( ${eg}==0 ));then echo "deny ${drop_Ip};">>$confdir #把“deny IP;”语句写入封锁配置文件中 echo ">>>>> `date '+%Y-%m-%d %H%M%S'` - 发现攻击源地址 -> ${drop_Ip} " >> /usr/local/data/nginx/logs/nginx_deny.log #记录log fi done
systemctl reload nginx
|
定时执行
1 2 3 4 5 6
| #!/bin/bash sed -i 's/^/#&/g' /usr/local/nginx/conf/
blockip.conf #把nginx封锁配置文件中的内容注释掉
systemctl reload nginx #重置nginx服务,这样就做到了解锁IP
|