HAProxy 通过 stick-table 在内存中记录源 IP 的请求频率,配合 deny 动作实现速率限制。适用于 HTTP/HTTPS 七层流量清洗,风险在于可能误伤共享出口 IP 的正常用户。
先说结论:HAProxy 防 CC 攻击的核心是使用 stick-table 统计请求频率并触发拒绝策略。
- 先判断:确认攻击流量特征是基于 IP 高频请求还是特定 URL 高频访问。
- 优先做:在 frontend 段落定义 stick-table 并设置 http_req_rate 阈值。
- 再验证:通过日志观察被拒绝请求的状态码及来源 IP 分布。
命令速用版
以下配置片段可直接放入 HAProxy 配置的 frontend 段落,实现每 10 秒内单 IP 超过 100 请求则拒绝。
frontend http_front
stick-table type ip size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 100 }为什么会这样
stick-table 是 HAProxy 内置的键值存储结构,专门用于保存 counters。
HAProxy 在处理请求时会将指定条件(如源 IP)作为 key 存入表格,并自动累加请求计数。当计数超过设定阈值时,触发 deny 动作直接断开连接,无需后端服务器参与,从而保护后端资源。
分步处理
步骤 1:定义 stick-table
在 frontend 或 backend 段落开头定义表格类型和存储内容。type ip 表示按 IP 存储,store http_req_rate(10s) 表示统计 10 秒内的请求速率。
步骤 2:追踪请求源
使用 http-request track-sc0 src 命令告诉 HAProxy 将当前请求的源 IP 记录到索引为 0 的 stick-table 中。
步骤 3:设置拒绝规则
使用 http-request deny 配合 fetch 表达式 sc_http_req_rate(0) 读取计数。gt 100 表示超过 100 次即拒绝。deny_status 429 返回 Too Many Requests 状态码。
步骤 4:重载配置
执行 haproxy -c -f /etc/haproxy/haproxy.cfg 检查语法,确认无误后 systemctl reload haproxy 生效。
怎么验证是否生效
查看 HAProxy 日志中是否出现状态码 429 的记录。
使用压测工具或脚本对同一 IP 发起高频请求,观察超过阈值后是否立即返回 429。同时监控 HAProxy 进程内存占用,确认 stick-table 未导致内存异常增长。
常见坑
NAT 环境误伤:如果用户处于大型 NAT 网关后(如公司出口、移动网络),多个用户共享一个公网 IP,速率限制可能误封正常用户。
内存消耗:stick-table 存储在内存中,size 设置过大会消耗过多内存,设置过小会导致旧数据过早淘汰,需根据并发 IP 数量调整。
SSL 终止位置:如果 HAProxy 前端是 TCP 模式且未终止 SSL,无法获取 HTTP 请求频率,必须在 backend 或 SSL 终止后的 frontend 配置。
常见问题
如何给特定 IP 设置白名单?
使用 ACL 匹配可信 IP 段并在 deny 规则前跳过。
配置 acl is_whitelist src 192.168.1.0/24,然后在 deny 行添加 if !{ is_whitelist } 条件。
限制特定 URL 而不是全局限速怎么办?
将 track-sc 和 deny 规则放在特定的 backend 或使用 path 匹配 ACL。
在 http-request 规则中增加 if { path_beg /api } 条件,仅对特定路径启用限速。
stick-table 数据重启后会丢失吗?
是的,stick-table 数据仅存储在内存中,重启 HAProxy 后计数器清零。
这属于正常设计,防 CC 主要关注实时流量,无需持久化历史数据。
参考来源
- HAProxy Technologies, "HAProxy Configuration Manual", https://www.haproxy.com/documentation/haproxy-configuration-manual/
- HAProxy Technologies, "Stick Tables", https://www.haproxy.com/documentation/hapee/latest/configuration/section-7.html#7.2