Limitação de taxa usando haproxy por URL por IP

Limitação de taxa usando haproxy por URL por IP

Nossos servidores estão sendo atacados por alguém constantemente. Não é DDOS. Apenas um IP atinge um URL mais de 200 vezes por segundo. Atualmente estou bloqueando o usuário por tabelas de ip. Estamos usando HAproxy para balanceamento de carga. Existe uma maneira de limitar um usuário com base em seu IP e no URL acessado?

Não quero bloquear apenas com base no IP, pois os usuários com NAT podem ser afetados. Digamos que eu queira mostrar a página de erro 503 se um determinado IP estiver acessando o mesmo URL como www.example.com/somepage.php?some=option&other=option2 mais de 3.000 vezes em 5 minutos? Isso significa que o mesmo IP pode acessar outros URLs como www.example.com/somepage.php?another=someotheroption.

Responder1

Esta solução requer pelo menos haproxy 1.6.

Primeiro, adicione o seguinte ao frontend:

http-request set-header X-DOS-Protect %[src];%[req.fhdr(host)]%[capture.req.uri]

Em seguida, adicione o seguinte ao back-end:

stick-table type integer size 1m expire 5m store http_req_rate(5m)
tcp-request inspect-delay 5s
tcp-request content track-sc0 req.fhdr(X-DOS-Protect),crc32(1) if HTTP
http-request tarpit if { sc0_http_req_rate gt 3000 }

Não consegui encontrar uma maneira de fazer o rastreamento no frontend, pois não encontrei uma maneira de aplicar um conversor naquela string concatenada que compõe o cabeçalho do X-DOS-Protect.

Estou aplicando a função hash para garantir que você não armazene uma string enorme na tabela stick, pois isso poderia facilmente levar a uma negação de serviço. Se você acha que esta função hash não é adequada para você devido a muitas colisões possíveis, você também pode aumentá-la aplicando crc32 a cada um dos componentes concatenados (e, é claro, removendo-o ao armazenar os dados e mudar para um maior armazenamento de mesa fixa), assim:

http-request set-header X-DOS-Protect %[src,crc32(1)];%[req.fhdr(host),crc32(1)]%[capture.req.uri,crc32(1)]

stick-table type string len 30 size 1m expire 5m store http_req_rate(5m)
tcp-request inspect-delay 5s
tcp-request content track-sc0 req.fhdr(X-DOS-Protect) if HTTP
http-request tarpit if { sc0_http_req_rate gt 3000 }

Observe que esta última solução utilizará mais de 7 vezes mais memória que a primeira, para cada entrada na tabela stick. É claro que o risco de colisão também seria bem menor.

informação relacionada