原创

基于Nginx日志通过iptables自动封禁恶意IP的脚本

分享一个自动封禁恶意IP的脚本,这个脚本的核心框架来源于互联网上某位大佬的分享,在其基础上结合了日常生产环境使用情况做了本地化的适配,分享出来供大家参考。

这个脚本的核心逻辑是:实时监控Nginx访问日志,当发现异常状态码(400、403、404、500)的时候,通过调用iptables命令来实现封禁恶意IP功能。

一、Nginx日志格式调整

为了方便获取Nginx访问日志的状态码和客户端IP,需要调整Nginx日志格式:

a.将status字段调整到末位;

b.将host字段调整到倒数第二位;

c.将remote_addr字段调整到首位;

d.将http_x_forwarded_for字段调整到正数第二位,并使用双引号括起来。

其他字段可以根据需要自定义,我的Nginx日志格式配置如下:

    log_format  main  '$remote_addr "$http_x_forwarded_for" $remote_user [$time_local] "$request" '
                      '$body_bytes_sent "$http_referer" "$http_user_agent" '
                      '"$request_time" "$upstream_response_time" "$scheme" "$host" $status';

二、部署IP封禁脚本

1.初始化环境

部署脚本的时候,需要修改脚本中log_path字段为脚本所在目录,同时在该目录下新建iptables.22文件与info、iptables文件夹:

比如将脚本放在/data/blacklist目录下,可以用如下命令建立:

mkdir -p /data/blacklist/{info,iptables}
iptables-save > /data/blacklist/iptables.22

2.自动封禁IP脚本完整内容

#!/bin/bash
source /etc/profile
log_path=/data/blacklist
now_time=$(date "+%Y-%m-%d %H:%M:%S")

start(){
BAN_CODES="400 404 403 500"
while true; do
    tail -n 0 -F /var/log/nginx/access.log |while read -r line; do
        CODE=$(echo "$line"|awk '{print $NF}')
        if [[ "$BAN_CODES" == *"$CODE"* ]];then
            echo "$line" >>$log_path/info/$(date +%Y%m%d).log
            IP=$(echo "$line"|awk '{gsub(/\"/,"",$2);print $2}')
            if [[ "$IP" == "-" ]];then
                IP=$(echo "$line"|awk '{print $1}')
            fi
            if [[ "$IP" != "127.0.0.1" ]];then
                iptables -A INPUT -s $IP -j DROP
                echo "$(date "+%Y-%m-%d %H:%M:%S")  $IP:已封禁" >>$log_path/log.log
            fi
        fi
    done
done
}

kill(){
 iptables -I INPUT -s $1 -j DROP
 echo "$now_time  封禁了:$1" >>$log_path/log.log
}

remove(){
  iptables -D INPUT -s $1 -j DROP
  echo "$now_time  解封了:$1" >>$log_path/log.log
}

show(){
  iptables -vnL
}

logs(){
  tail -f /var/log/nginx/access.log
}

log(){
  awk '{print $1}' /var/log/nginx/access.log |sort |uniq -c|sort -n
}

url(){
  awk -v p="${1:-}" '(p == "" || $(NF-1) ~ p) {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -k1 -n -r | more
}


uban(){
  iptables -vnL >$log_path/iptables/iptables$(date +%Y%m%d).show
  iptables-save >$log_path/iptables/iptables$(date +%Y%m%d).bak
  iptables -F
  echo "$now_time  清除历史封禁ip" >>$log_path/log.log
  iptables-restore <$log_path/iptables.22
  echo "$now_time  加载历史封禁规则" >>$log_path/log.log
} 
status(){
 if [ -n "$1" ];then
    awk -v temp=$1 '{if($NF==temp)print $0}' /var/log/nginx/access.log|more
 fi
 awk '{print $NF}' /var/log/nginx/access.log |sort |uniq -c|sort -n
}
showlog(){
ip=$1
results=$(cat log.log |grep $ip |grep 已封禁 |awk '{print $1}'| sort | uniq)
if [ -z "$results" ];then
    echo "未找到该ip封禁记录"
else 
    for result in $results;do
        logdate=$(echo $result |awk '{print $1}')
        filename=$(date -d $logdate +%Y%m%d).log
        if [ -f "info/$filename" ] ; then
            echo "匹配时间:$result"
            echo "日志文件名称:$filename"
            echo "日志内容:"
            cat info/$filename |grep --color=auto $ip 
            echo "==================================================================================="
            echo "==================================================================================="
        else
            echo "未找到日志文件:$filename"
        fi
    done
fi
}
msg="start 启动IP自动封禁
log 打印访问IP记录
logs 显示nginx实时日志
kill 手动封禁单IP
show 显示当前规则
remove 手动解封IP
url 查看请求频率最高url
uban 解除全部IP封禁
status 查看日志状态码
showlog 查看封禁IP日志"
case "$1" in
    start) start ;;
    log) log ;;
    url) url $2 ;;
    logs) logs ;;
    kill) kill $2 ;;
    remove) remove $2 ;;
    show) show ;;
    uban) uban ;;
    status) status $2 ;;
    showlog) showlog $2 ;;
    *) echo "$msg" ;;
esac

三、使用脚本自动封禁IP

1.直接后台启动脚本

nohup sh blacklist.sh start

2.使用systemctl服务管理脚本运行

创建服务文件,复制到/usr/lib/systemd/system/目录下,文件内容如下:

[Unit]
Description=IP Blacklist Monitoring Service
After=network.target

[Service]
User=root
WorkingDirectory=/data/blacklist
ExecStartPre=/bin/bash -c '/data/blacklist/blacklist.sh uban'
ExecStart=/bin/bash -c '/data/blacklist/blacklist.sh start'
Restart=on-failure
RestartSec=3
Environment="PATH=/usr/local/bin:/usr/bin:/bin"

[Install]
WantedBy=multi-user.target

注:需要将路径修改为实际脚本位置。

重新加载systemd配置并设置开机启动:

systemctl daemon-reload
systemctl enable blacklist
systemctl start blacklist

四、脚本其他常用功能

1.查看状态码统计

查看状态码分布情况:

sh blacklist.sh status

查看指定状态码详细日志:

sh blacklist.sh status 404

2.封禁单个IP

sh blacklist.sh kill 192.168.1.100

3.解封指定IP

sh blacklist.sh remove 192.168.1.100

4.实时显示Nginx访问日志

sh blacklist.sh logs

5.查看请求url统计

全站请求url统计详情:

sh blacklist.sh url

单独blog站点的url统计详情:

sh blacklist.sh url blog

6.查看指定IP历史封禁记录

sh blacklist.sh showlog 192.168.1.100

扩展说明:

1.脚本中所有涉及iptables的操作都需要root权限。

2.脚本默认监控日志为/var/log/nginx/access.log,如果Nginx日志在其他位置需要修改脚本中的路径。

正文到此结束
本文目录