这是示例配置,
frontend fe_app
bind 0.0.0.0:8484 name http
acl has_auth_header req.fhdr(api-key) -m found
acl mark_as_abuser sc0_inc_gpc0(be_429_table_api) gt 10
acl req_rate_api_abuse sc0_http_req_rate(be_429_table_api) gt 10
http-request set-header X-Concat %[req.fhdr(api-key)]_%[src] if has_auth_header
http-request track-sc0 req.fhdr(X-Concat) table be_429_table_api if has_auth_header
capture request header X-Concat len 100
use_backend be_429_slow_down if mark_as_abuser req_rate_api_abuse has_auth_header
default_backend be_default
backend be_429_table_api
stick-table type string size 100k expire 10s store http_req_rate(10s),http_req_cnt,gpc0,gpt0
backend be_429_slow_down
timeout tarpit 10s
http-request tarpit
我测试了watch -n2 'echo "show table be_429_table_api" | socat stdio unix:/var/run/haproxy.sock'
问题出现在收到请求时gpc0 自动开始增加。直到表过期。这似乎与任何方式都无关http_req_rate
。那么这个计数器的用途是什么?
我想要一个计数器,只有当 http_req_rate >10 时才会增加。因此,当它超过 3(即攻击者在 1 分钟内重复超过 3 次)时,我可以阻止。类似以下内容
1)下午 2:00:00 :http_req_rate > 10,abuae_counter =1
2)下午 2:00:07:http_req_rate > 10,abuse_counter = 2
3)下午 2:00:17 :http_req_rate > 10 abuse_counter =3
4)下午 2:00:45:http_req_rate > 10 abuse_counter =4 > 阻止
然后我可以简单地使用
use_backend be_429_slow_down if abuse_counter has_auth_header
如何实现?我考虑过使用 lua 或 set.var,但没有任何效果。
答案1
如果你想要一个带有大时间片的简单计数,你可以使用
frontend website
bind :80
stick-table type ip size 100k expire store http_req_rate(24h)
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 }
default_backend servers
我从 stick 表中删除了 expires 参数,如文档中所述:
A stick table record expires and is removed after a period of inactivity by the client, as set by the expire parameter. That’s just a way of freeing up space. Without an expire parameter, oldest records are evicted when the storage becomes full