Nginx 日志安全分析实操指南
一 基础准备与日志规范
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
反向代理或 CDN 前置时,建议用 map 规范化真实 IP:map $http_x_forwarded_for $real_ip {
default $remote_addr;
"~^(\d+\.\d+\.\d+\.\d+)" $1;
}
二 关键检测项与快速命令
TIME_WINDOW=$(date --date='1 minute ago' '+%d/%b/%Y:%H:%M')
awk -v w="$TIME_WINDOW" '$4 ~ "\\["w":" {print $1}' /var/log/nginx/access.log \
| sort | uniq -c | sort -nr | head
egrep -i '\.(git|svn|env|sql|bak|zip|rar|tar|gz|log|cgi|asp|aspx|jsp|php[3-7]?)$|\
(wp-login|phpmyadmin|admin|administrator|backup|config|shell|upload|test|\.ht)' \
/var/log/nginx/access.log | awk '{print $1,$7}' | sort | uniq -c | sort -nr
# 4xx/5xx Top
awk '$9 ~ /^[45]/ {print $1,$7,$9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
# 大量 302 到 .php
awk '$9 == 302 && $7 ~ /\.php$/ {print $1,$7,$9}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
awk -F\" '$6 ~ /^-$|curl|python|scanner|bot|spider|wget|nikto|sqlmap|nmap/ {print $1,$6,$7}' \
/var/log/nginx/access.log | sort | uniq -c | sort -nr
# 响应体异常大(>1MB)
awk '$10 > 1048576 {print $1,$7,$10}' /var/log/nginx/access.log | sort -nr | head
# 响应体异常小(如 0 或极小)
awk '$10 < 100 && $9 ~ /200/ {print $1,$7,$10}' /var/log/nginx/access.log | sort | uniq -c | sort -nr
awk '$11 !~ /yourdomain/ && $6 ~ /"Mozilla/5\.0"/ {print $1,$7,$11,$6}' \
/var/log/nginx/access.log | sort | uniq -c | sort -nr
grep -iE 'permission denied|no such file|index forbidden|failed \(2|open.*failed' \
/var/log/nginx/error.log | tail -n 50
三 自动化检测与封禁
#!/usr/bin/env bash
LOG=/var/log/nginx/access.log
TIME_WIN=$(date --date='1 minute ago' '+%d/%b/%Y:%H:%M')
THRESHOLD=200
BAN_TIME=3600
WHITELIST=("127.0.0.1" "192.168.0.0/24")
is_whitelisted() {
local ip=$1
for w in "${WHITELIST[@]}"; do
if [[ $ip == $w ]] || { [[ $w == *"/"* ]] && command -v ipcalc >/dev/null &&
ipcalc -nb "$w" "$ip" 2>/dev/null | grep -q "YES"; }; 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
# 自动解封
(sleep "$BAN_TIME" && iptables -D INPUT -s "$ip" -j DROP 2>/dev/null) &
fi
fi
done
使用要点:配置 **crontab * * * * *** 高频执行;加入 白名单;记录封禁日志;必要时改用 firewalld 的 rich rule。四 集中化与可视化分析
| 平台 | 适用场景 | 关键要点 |
|---|---|---|
| ELK Stack | 海量日志、复杂检索与可视化 | 借助 Ingest Pipeline 解析日志,Kibana 建立安全看板与阈值告警 |
| Graylog | 轻量部署、快速合规审计 | 内置管道与告警,易与 LDAP/AD 集成 |
| Loki + Grafana | 云原生、低成本 | Promtail 采集,Grafana 统一监控与安全面板 |
| Splunk | 商业化、强告警与合规 | 丰富 App 生态,适合企业级 SOC |
五 防护加固与最佳实践