这段脚本的作用是通过分析 Nginx 的访问日志,检测异常的 IP 地址,并使用 iptables
封禁这些 IP。
bash
#!/bin/bash
# 配置变量
LOG_FILE="/usr/local/nginx/logs/access.log"
THRESHOLD=10
DROP_LOG_FILE="/tmp/drop_ip.log"
DATE=$(date +"%d/%b/%Y:%H:%M")
# 检测异常 IP
ABNORMAL_IP=$(tail -n5000 "$LOG_FILE" | grep "$DATE" | awk '{a[$1]++} END {for(i in a) if(a[i]>'$THRESHOLD') print i}')
# 封禁异常 IP
for IP in $ABNORMAL_IP; do
# 检查 IP 是否已经被封禁
if ! iptables -C INPUT -s "$IP" -j DROP &> /dev/null; then
# 封禁 IP
iptables -I INPUT -s "$IP" -j DROP
echo "$(date +'%F_%T') $IP - Access count exceeded threshold ($THRESHOLD)" >> "$DROP_LOG_FILE"
fi
done
以下是脚本的详细解析和一些需要注意的地方:
脚本功能
-
配置变量:
-
LOG_FILE
:指定 Nginx 的访问日志文件路径。 -
THRESHOLD
:设置访问次数的阈值,超过此值的 IP 将被认定为异常。 -
DROP_LOG_FILE
:记录被封禁 IP 的日志文件路径。 -
DATE
:获取当前时间,格式为日/月/年:时:分
,用于筛选日志中当前时间的记录。
-
-
检测异常 IP:
-
使用
tail -n5000 "$LOG_FILE"
获取日志文件的最后 5000 行。 -
使用
grep "$DATE"
筛选出当前时间的记录。 -
使用
awk
统计每个 IP 的访问次数,并筛选出访问次数超过阈值的 IP。
-
-
封禁异常 IP:
-
遍历检测到的异常 IP。
-
使用
iptables -C INPUT -s "$IP" -j DROP
检查该 IP 是否已经被封禁。 -
如果未被封禁,则使用
iptables -I INPUT -s "$IP" -j DROP
将其封禁,并将封禁信息记录到DROP_LOG_FILE
中。
-
注意事项
-
日志格式依赖:
- 脚本假设 Nginx 的日志格式是标准的 Combined Log Format,其中第一个字段是 IP 地址。如果日志格式不同,需要调整
awk
的字段索引。
- 脚本假设 Nginx 的日志格式是标准的 Combined Log Format,其中第一个字段是 IP 地址。如果日志格式不同,需要调整
-
时间格式匹配:
DATE
的格式需要与 Nginx 日志中的时间格式完全匹配。如果日志中的时间格式不同(例如包含毫秒或时区信息),脚本可能无法正确筛选记录。
-
权限问题:
- 脚本需要以 root 用户运行,因为
iptables
命令需要管理员权限。
- 脚本需要以 root 用户运行,因为
-
性能问题:
- 如果日志文件非常大,
tail -n5000
和grep
操作可能会消耗较多资源。可以考虑优化日志处理方式,例如定期清理日志或使用更高效的数据处理工具。
- 如果日志文件非常大,
-
误封风险:
- 脚本简单地根据访问次数封禁 IP,可能会误封正常用户(例如爬虫或高频访问的合法用户)。建议结合其他检测机制(如访问频率、请求类型等)来提高准确性。
-
日志记录:
- 封禁日志记录到
/tmp/drop_ip.log
,但/tmp
目录可能会被定期清理。建议将日志存储到更安全的路径,例如/var/log
。
- 封禁日志记录到
改进建议
-
日志格式检查:在脚本开头检查日志文件是否存在以及是否符合预期格式。
-
动态阈值:根据流量情况动态调整阈值,而不是固定值。
-
白名单机制:维护一个白名单,避免误封重要 IP。
-
持久化封禁规则 :使用
iptables-save
和iptables-restore
保存和恢复规则,避免系统重启后规则丢失。 -
日志清理:定期清理封禁日志文件,避免文件过大。