- 关于iptables定时策略、crontab设置请自行去了解,建议使用"nohup"方式执行crontab任务;
- 对于nginx error日志可以做大小限制进行截断以减少脚本读取日志文件耗时;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# !/bin/bash # 脚本用于nginx错误URL访问检测 # 若指定时间内来源IP地址错误URL超出合理范围, 则视为URL嗅探源并通过防火墙阻止访问 # 说明: 函数内部变量使用小写字母, 脚本头部变量使用大写字母 # 变量引用:${}可以拼接字符且兼容unix,$不可以拼接字符 # sh -x ngx_err_block.sh 进行跟踪调试 # 清理10分钟前的旧日志文件 for TYPE in {log,run} do find /data/shell/ -type f -name "*ngx*.$TYPE" -mmin +10 -exec rm -f {} \; done # 定义程序、日志相关变量, 日志路径可以参考以下示例自行设置 # error_page 400 403 404 500 502 504 /404.html; # location = /404.html { # access_log /data/nginx/log/error_request.log main; # } BINGIPTAB="/sbin/iptables" NGXLOG="/data/nginx/log/error_request.log" NGX00="/data/shell/$(date +%Y%m%d)_ngx00_$.log" NGX30="/data/shell/$(date +%Y%m%d)_ngx30_$.log" NGX60="/data/shell/$(date +%Y%m%d)_ngx60_$.log" IPTABLST="/data/shell/$(date +%Y%m%d)_ngx_$.lst" RUNLOG="/data/shell/$(date +%Y%m%d)_ngx_$.run" CHAIN_NM="IN_NGXBLOCK" PORTS="80,443" GREP_VWORD="crayon-syntax-highlighter|wp-pagenavi|open-social|^$" GREP_VCODE="200|304|503" # 定义函数: 统计一段时间内某个IP地址访问出错的次数 function errsum(){ # 读取IP地址 IPADDR=$(echo ${line} | awk -F" " '{print $2}') # 读取IP首次汇总数据中访问失败的次数, 最小值计 0 NUMS=$(grep -w ${IPADDR} ${NGX00} | awk -F" " '{print $1}') if [ "$NUMS" = "" ]; then NUMS=0 fi # 读取IP此次汇总数据中访问失败的次数 NUME=$(echo ${line} | awk -F" " '{print $1}') # 一段时间内的IP总计访问失败的次数 NUMC=$(expr ${NUME} - ${NUMS}) # 将汇总数据中每个IP访问失败的次数进行记录 echo $IPADDR $NUME $NUMS $NUMC >> $RUNLOG } # 定义函数: 将访问失败过高的IP地址加入防火墙规则 function addrule(){ # 主判断:IP一段时间内访问失败的次数是否大于命令第一个参数值, 如果值为真则执行 # 注意:if [] 内的两个值要么都加"", 要么都不加, 避免报错(integer expression expected) if [ $NUMC -gt $1 ]; then # 检索系统当前防火墙规则中是否存在$CHAIN_NM链 $BINGIPTAB -nL $CHAIN_NM if [ $? -ne 0 ]; then # 如果规则链不存在, 则新建规则链并应用到INPUT链首行 $BINGIPTAB -N $CHAIN_NM $BINGIPTAB -I INPUT 1 -j $CHAIN_NM fi # 规则链存在, 判断链中条目数量是否超过1000条 chain_sum=$(${BINGIPTAB} --line-numbers -nvL ${CHAIN_NM} | tail -n 1 | cut -d' ' -f 1) # 规则链存在但是列表为空, 则赋值为0; num 为输出表头 if [ "$chain_sum" = "num" ]; then chain_sum=0 fi if [ $chain_sum -gt 1000 ]; then # 如果链中规则数量大于1000条, 则删除末行规则 $BINGIPTAB -D $CHAIN_NM $chain_sum fi # 检查现有规则中是否存在将要阻止的IP地址 if [ "$(${BINGIPTAB} -nL ${CHAIN_NM} | grep -w ${IPADDR} | grep DROP)" ]; then # 如果要阻止的IP地址已经在现有规则中, 查询行号并删除旧规则, 确保每个IP在链中只有一个条目 # 建议:如果有其他应用检测脚本要调用iptables, 请使用不同的链名称 # 说明:--kerneltz 在 RHEL/CentOS 6.x 中应替换为 --localtz 参数, 检查系统时间和时区设置 chain_num=$(${BINGIPTAB} --line-numbers -nL ${CHAIN_NM} | grep -w $(echo ${IPADDR}) | grep DROP | cut -d' ' -f 1) $BINGIPTAB -D $CHAIN_NM $chain_num # 插入新规则到链首行, 多次被block的IP将阻止15min内访问, 不指定日期则截止至 2038-01-19 $BINGIPTAB -I $CHAIN_NM 1 -s $IPADDR -p tcp -m multiport --dports $PORTS \ -m time --timestart $(date +%H:%M:%S) --timestop $(date -d '+15 min' +%H:%M:%S) \ --datestop $(date +%Y-%m-%dT23:59:59) --kerneltz -j DROP else # 如果要阻止的IP地址不在现有规则中, 插入新规则到链首行 # 首次被block的IP将阻止10min内访问,不指定日期则截止至 2038-01-19 $BINGIPTAB -I $CHAIN_NM 1 -s $IPADDR -p tcp -m multiport --dports $PORTS \ -m time --timestart $(date +%H:%M:%S) --timestop $(date -d '+10 min' +%H:%M:%S) \ --datestop $(date +%Y-%m-%dT23:59:59) --kerneltz -j DROP fi fi } # 执行第一次NGINX访问错误信息汇总, 打印某列数值的和: awk '{sum+=$1} END {print sum}' # grep -a 是为了避免Nginx日志变成bin格式。 grep -ahvE "${GREP_VWORD}" $NGXLOG | cut -d'"' -f 1,3 | awk '{print $1,$7}' | grep -vE "${GREP_VCODE}" | \ awk '{sum[$1]++} END {for (i in sum) {print sum[i],i | "sort -nr -k 1"}}' | awk '{if ($1 > 5) print $0}' > $NGX00 # 执行第二次NGINX访问错误信息汇总 sleep 30 grep -ahvE "${GREP_VWORD}" $NGXLOG | cut -d'"' -f 1,3 | awk '{print $1,$7}' | grep -vE "${GREP_VCODE}" | \ awk '{sum[$1]++} END {for (i in sum) {print sum[i],i | "sort -nr -k 1"}}' | awk '{if ($1 > 5) print $0}' > $NGX30 #检索30秒钟内访问出错次数超过6次的IP地址加入防火墙策略 cat $NGX30 | while read line do errsum addrule 6 done #清空RUNLOG内容避免重复记录被导入 echo > $RUNLOG # 执行第三次NGINX访问错误信息汇总 sleep 30 grep -ahvE "${GREP_VWORD}" $NGXLOG | cut -d'"' -f 1,3 | awk '{print $1,$7}' | grep -vE "${GREP_VCODE}" | \ awk '{sum[$1]++} END {for (i in sum) {print sum[i],i | "sort -nr -k 1"}}' | awk '{if ($1 > 5) print $0}' > $NGX60 #检索60秒钟内访问出错次数超过10次的IP地址加入防火墙策略 cat $NGX60 | while read line do errsum addrule 10 done |
文章出自: 本站技术文章均为原创,版权归 "Desen往事 - 个人博客" 所有;部分图片来源于 Yandex ,转载本站文章请注明来源。
本文标题:Nginx错误日志分析及防护脚本