温馨提示×

如何利用Nginx日志监控异常流量

小樊
37
2025-11-24 18:22:43
栏目: 编程语言

总体思路与指标设计

  • 从访问日志中抽取可量化的时序指标,按时间窗口做统计与阈值告警,覆盖“量、质、行为”三个维度:
    • 量:每分钟请求数(按IP/URI/UA/Referer/Status分桶),突增即告警。
    • 质:错误率(如5xx/4xx占比)、慢响应(如upstream_response_time超过阈值)。
    • 行为:敏感路径扫描(如**/wp-login.php、/phpmyadmin**)、异常UA、异常Header/Cookie、POST/PUT 高频等。
  • 日志建议输出为JSON,便于解析与聚合;关键字段包含:@timestamp、clientip、request、status、http_user_agent、http_referer、uri、body_bytes_sent、request_time、upstream_response_time、host。示例格式:
    log_format json '{"@timestamp":"$time_iso8601","clientip":"$remote_addr","request":"$request",'
                    '"http_user_agent":"$http_user_agent","size":"$body_bytes_sent",'
                    '"responsetime":"$request_time","upstreamtime":"$upstream_response_time",'
                    '"http_host":"$host","url":"$uri","referer":"$http_referer","status":"$status"}';
    access_log /var/log/nginx/access.log json;
    
    以上做法便于后续用脚本、日志导出器或流式计算做指标统计与告警。

快速落地方案 Shell脚本分钟级统计与告警

  • 目标:统计过去1分钟内单IP请求次数,超过阈值(如300次/分)触发邮件告警,并输出Top N供排查。
  • 示例脚本要点(按你的日志时间格式调整时间字段截取):
    #!/usr/bin/env bash
    set -euo pipefail
    LOG=/var/log/nginx/access.log
    NOW=$(date +%H:%M:%S)
    START=$(date -d '1 minute ago' +%H:%M:%S)
    
    # 1) 按时间窗口筛选、统计Top IP;2) 阈值判断与告警
    tac "$LOG" | awk -v st="$START" -v et="$NOW" '
      {
        # 假设时间字段在第4列,形如 [24/Nov/2025:10:20:10 +0800]
        t = substr($4, 2, 8)   # 10:20:10
        if (t >= st && t <= et) print $1
      }' \
      | sort | uniq -c | sort -nr \
      | tee /tmp/ip_top10.txt \
      | while read cnt ip; do
          if (( cnt > 300 )); then
            # 发送告警(示例调用 Python 邮件脚本)
            /usr/bin/python /opt/send_mail.py "$ip" "$cnt"
          fi
        done
    
    要点:
    • 使用tac+awk按时间窗口扫描,避免重复统计与漏统计。
    • 阈值与窗口可按业务调整(如200次/分500次/分)。
    • 邮件脚本负责组装主题与正文(包含IP、次数、时间窗口、Top明细)。

自动封禁与防护策略

  • 日志分析后自动封禁(iptables/firewalld)
    • 思路:每分钟统计过去1分钟的IP请求数,超过阈值即加入防火墙DROP规则;先检查是否已封禁避免重复添加;支持白名单定时解封
    • 示例(iptables,阈值200次/分):
      #!/usr/bin/env bash
      LOG=/var/log/nginx/access.log
      TIME_WIN=$(date --date='1 minute ago' "+%d/%b/%Y:%H:%M")  # 与日志时间格式匹配
      THRESHOLD=200
      WHITELIST=("127.0.0.1" "192.168.0.0/24")
      
      is_whitelisted() {
        local ip=$1
        for w in "${WHITELIST[@]}"; do
          if [[ $w == *"/"* ]]; then
            ipcalc -nb "$w" "$ip" 2>/dev/null | grep -q "YES" && return 0
          elif [[ $ip == "$w" ]]; then
            return 0
          fi
        done
        return 1
      }
      
      grep "$TIME_WIN" "$LOG" | awk '{print $1}' | sort | uniq -c | sort -nr | while read cnt ip; do
        if (( cnt > THRESHOLD )) && ! is_whitelisted "$ip"; then
          if ! iptables -C INPUT -s "$ip" -j DROP 2>/dev/null; then
            echo "$(date) BAN $ip ($cnt req/min)" >> /var/log/nginx/ban.log
            iptables -A INPUT -s "$ip" -j DROP
            # 可选:定时解封(示例1小时后)
            (sleep 3600; iptables -D INPUT -s "$ip" -j DROP) &
          fi
        fi
      done
      
    • 如使用firewalld,可用 rich rule 替代 iptables 规则。
  • 更稳妥的工具与策略
    • 使用Fail2ban:内置Nginx日志匹配、自动封禁/解封、白名单、频率控制,减少自研脚本维护成本。
    • 结合WAF(如 OpenResty/ModSecurity)在入口层做特征拦截,日志用于审计与策略优化。

规模化与可视化方案

  • 架构建议:Nginx集群 → 日志采集(Filebeat/Logstash/Lua+Kafka)→ 消息队列(Kafka/Redis)→ 指标计算与告警(Logstash/Flink/Heka)→ 可视化(Grafana/Kibana)
  • 指标与告警示例:
    • 每分钟总QPS、按IP/URI/UA分桶的QPS突增告警。
    • 5xx/4xx错误率P95/P99响应时间异常告警。
    • 敏感路径命中率、异常UA/Referer占比、POST/PUT 高频异常。
  • 日志到监控的桥接
    • 使用prometheus-nginxlog-exporter将Nginx日志转为Prometheus指标,在Grafana配置阈值与告警规则,实现统一观测与告警。

进阶 基于时间序列的异常检测

  • 将每分钟聚合指标(如QPS、5xx数、P95时延)构造成时间序列,采用滑动窗口滞后特征,用RNN/LSTM/Prophet等模型学习正常模式并识别突增、周期破坏与异常形态。
  • 适用场景:周期性业务、节假日/活动期流量预测与偏差检测、缓慢型异常(持续劣化)识别。

0