适用场景
HTTP 洪水攻击(HTTP Flood)是 DDoS 攻击最常见形式之一。攻击者通过大量肉鸡或云服务发起海量看似合法的 GET/POST 请求,耗尽服务器的 CPU、内存或带宽资源,导致正常用户无法访问。本文适用于Nginx 反向代理环境的 Web 应用防护,包括各类 CMS、API 服务及电商平台。
前置条件
- Nginx 1.18+(已编译 ngx_http_limit_req_module 和 ngx_http_limit_conn_module)
- Python 3.6+(用于日志分析脚本)
- 服务器 root 权限
原理说明
HTTP 洪水与 Slowloris(慢速攻击)不同:Slowloris 通过保持连接不关闭耗尽连接池,而 HTTP 洪水以极快速度发送完整 HTTP 请求。关键区别在于请求速率(RPS)和请求特征分布。防御的核心是对比正常用户行为基线,识别异常高频访问并实施限流。
操作步骤
步骤一:Nginx 基础限流配置
首先在 nginx.conf 的 http 块中定义限流区域:
# /etc/nginx/nginx.conf -- http 块内
# 请求速率限制区域:基于客户端 IP
# rate=30r/s -- 平均每秒最多 30 个请求
# burst=50 -- 允许突发 50 个请求的缓冲
# nodelay -- 不延迟处理突发请求(超出直接拒绝)
limit_req_zone $binary_remote_addr zone=per_ip:10m rate=30r/s;
# 并发连接数限制:每个 IP 最多 20 个并发连接
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
# 服务器级别速率限制(全局限流)
limit_req_zone $server_name zone=global:10m rate=500r/s;
然后在特定 server/location 块中启用:
# /etc/nginx/conf.d/default.conf -- server 块内
server {
listen 443 ssl;
server_name your-site.com;
limit_req zone=per_ip burst=50 nodelay;
limit_conn conn_per_ip 20;
limit_req zone=global burst=1000 nodelay;
limit_req_status 429;
limit_conn_status 429;
error_page 429 /429.html;
location = /429.html {
root /var/www/html;
internal;
}
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 对登录/API 接口实施更严格限制
location /wp-login.php {
limit_req zone=per_ip burst=5 nodelay;
limit_conn conn_per_ip 5;
proxy_pass http://backend;
}
location /api/ {
limit_req zone=per_ip burst=10 nodelay;
limit_conn conn_per_ip 10;
proxy_pass http://backend_api;
}
}
步骤二:UA 与请求特征过滤
攻击者常使用固定或明显伪造的 User-Agent。在 Nginx 中实施UA 黑名单:
# UA 黑名单映射
map $http_user_agent $bad_ua {
default 0;
"~*curl" 1;
"~*wget" 1;
"~*python-requests" 1;
"~*Go-http-client" 1;
"~*Java/" 1;
"~*libwww-perl" 1;
"~*HTTPie" 1;
"" 1;
}
server {
if ($bad_ua) { return 403; }
}
注意:UA 过滤应谨慎使用,避免误伤爬虫和 API 客户端。更精确的做法是基于请求频率 + UA 组合判定。
步骤三:基于请求路径的精细化限流
limit_req_zone $binary_remote_addr zone=static:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=dynamic:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=search:10m rate=5r/s;
server {
# 静态资源 -- 放宽限制
location ~* \\.(jpg|jpeg|png|gif|css|js|ico|woff2?)$ {
limit_req zone=static burst=200 nodelay;
expires 30d;
add_header Cache-Control "public";
}
# 动态页面 -- 适中限制
location / {
limit_req zone=dynamic burst=20 nodelay;
}
# 搜索/查询 -- 严格限制
location ~* /(search|query|s\\.php) {
limit_req zone=search burst=5 nodelay;
}
}
步骤四:日志分析脚本
以下 Python 脚本分析 Nginx access.log,识别高频请求 IP 和攻击特征:
#!/usr/bin/env python3
"""
Nginx HTTP Flood 攻击特征分析脚本
用法: python3 flood_detect.py /var/log/nginx/access.log
"""
import sys, re, collections
LOG_PATTERN = re.compile(
r'(?P[\d.]+) .* \[(?P
步骤五:自动封禁脚本
#!/bin/bash
# auto_ban.sh -- 自动封禁高频 IP
LOG="/var/log/nginx/access.log"
BAN_LIST="/etc/nginx/conf.d/ban_ip.conf"
THRESHOLD=500
WINDOW=60
python3 flood_detect.py "$LOG" "$WINDOW" "$THRESHOLD" | grep "高频攻击" | \
awk '{print $1}' | while read ip; do
if ! grep -q "$ip" "$BAN_LIST" 2>/dev/null; then
echo "deny $ip;" >> "$BAN_LIST"
echo "[BAN] $ip"
fi
done
nginx -s reload
建议将此脚本加入 cron,每 5 分钟执行一次:
*/5 * * * * /usr/local/bin/auto_ban.sh >> /var/log/auto_ban.log 2>&1
配置验证
# 1. 检查 Nginx 配置语法
nginx -t
# 2. 使用 ab 模拟高频请求
ab -n 1000 -c 50 https://your-site.com/
# 3. 测试单 IP 限流
for i in $(seq 1 100); do
curl -s -o /dev/null -w "%{http_code}\\n" https://your-site.com/ &
done
# 正常应看到部分 429
# 4. 检查 access.log 中的 429 记录
grep "429" /var/log/nginx/access.log | head -10
常见问题
Q1: limit_req 的 burst 和 nodelay 如何配合?
burst=N 允许瞬时超过 rate 的请求先排队,超过 N 的直接拒绝。不加 nodelay 时,排队请求会按 rate 速度被处理(导致延迟)。加上 nodelay 后,排队请求立即被处理,但超出 burst 的请求直接拒绝。推荐对 API 服务使用 nodelay,对正常页面访问可以不加 nodelay 以获得更平滑的限流效果。
Q2: 限流后如何区分正常用户爆发与攻击?
关注三个特征:请求路径分布(攻击者通常集中在少数几个路径)、User-Agent 多样性(攻击者 UA 往往单一或明显伪造)、来源 IP 分布(正常 CDN 回源 IP 固定,攻击 IP 分散)。建议对判定为”可疑”的 IP 先返回 429(非 403),配合前端 JS Challenge 验证(如 reCAPTCHA)进一步确认。
总结
HTTP 洪水攻击防御需要组合使用 Nginx 的多层限流机制:limit_req(请求速率)、limit_conn(并发连接数)、UA 过滤以及基于日志分析的自适应封禁。没有万能配置,需要根据实际业务流量持续调优参数。配合 CDN 层 WAF 和云端 DDoS 防护(如 Cloudflare、阿里云 DDoS 高防)可构建更完善的防御体系。