HAProxy 防止 DDoS 攻击主要依靠 stick-table 跟踪状态,配合 deny 规则拦截。针对四层连接洪水使用 conn_rate,针对七层 CC 攻击使用 http_req_rate。
先说结论:通过内存表记录源 IP 请求速率,超过阈值拒绝。四层断连接,七层返回 403。
- 先判断:区分攻击类型,连接洪水用四层,CC 攻击用七层。
- 优先做:开启 Stats Socket 以便验证,配置 stick-table 和 deny 规则。
- 再验证:通过 Socket 查看表计数,观察日志确认拦截动作。
四层与七层策略选择
HAProxy 可在不同层级实施限制,需根据攻击特征选择:
- 四层限制 (TCP):使用
conn_rate。适用于 SYN Flood 或连接耗尽攻击。优点是处理快,缺点是拒绝后客户端看到连接重置,无 HTTP 状态码。 - 七层限制 (HTTP):使用
http_req_rate。适用于 CC 攻击(模拟正常 HTTP 请求)。优点是精准,可返回 403 状态码,缺点是消耗稍多 CPU。
前置配置:开启 Stats Socket
为了验证限制是否生效,需开启管理 Socket。在 global 段落添加:
global
stats socket /var/run/haproxy.sock mode 600 level admin
...
重载 HAProxy 后,确保该 socket 文件存在且权限正确。
配置示例:四层连接频率限制
适用于防御连接洪水。在 frontend 中配置:
frontend http_front
bind *:80
stick-table type ip size 100k expire 30s store conn_rate(10s)
tcp-request connection track-sc0 src
tcp-request connection deny if { sc_conn_rate(0) gt 50 }
default_backend web_servers
注意:此配置会在 TCP 握手阶段拒绝,客户端无法建立连接,日志中无 HTTP 状态码。
配置示例:七层 HTTP 频率限制
适用于防御 CC 攻击。在 frontend 或 backend 中配置:
frontend http_front
bind *:80
stick-table type ip size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny deny_status 403 if { sc_http_req_rate(0) gt 100 }
default_backend web_servers
注意:此配置会返回 HTTP 403 Forbidden,适合需要明确告知客户端被拒的场景。
日志配置与验证
确保日志记录拒绝行为。在 defaults 或 frontend 中启用日志:
defaults
log global
option httplog
验证步骤:
- 查看 Stick-Table:使用命令
echo "show table http_front" | socat stdio /var/run/haproxy.sock。确认 IP 是否存在且计数增加。 - 测试触发限制:使用压测工具高频请求。四层限制表现为连接失败,七层限制表现为返回 403。
- 检查日志:查看
/var/log/haproxy.log,七层拒绝会记录状态码 403,四层拒绝可能仅记录连接中断。
常见坑与缓解
- 内存溢出:
size设得太大可能耗尽内存。建议根据服务器内存调整,例如 100k 约占用几十 MB,需预留余量。 - NAT 误伤: 公司出口或基站 NAT 会导致大量用户共用 IP。缓解方案:调高阈值,或在 HAProxy 前部署 CDN 清洗流量,或通过
X-Forwarded-For获取真实 IP(需配合src信任配置)。 - 长连接影响: 若客户端使用 Keep-Alive,
conn_rate可能较低但请求量巨大。防御 CC 攻击请优先使用http_req_rate。 - 分布式攻击: 单点频率限制无法防御分布式低速率攻击,需结合全局防火墙或云防护。