Pular para conteúdo

abuse-guard: Auto-banir clientes abusivos pela taxa de resposta de erro

Requer o plano Pro (ou superior) da assinatura GetPageSpeed NGINX Extras.

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-abuse-guard
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-abuse-guard

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_abuse_guard_module.so;

Este documento descreve nginx-module-abuse-guard v2.0.0 lançado em 19 de julho de 2026.


Seu log de erros é uma confissão. Abuse Guard o lê em tempo real e bloqueia abusadores.

Todo scanner, fuzzer e bot de preenchimento de credenciais deixa a mesma impressão digital: um spray de 404s caçando caminhos ocultos, 403s batendo em portas trancadas, solicitação falhada após solicitação falhada. Abuse Guard observa os códigos de status que seu servidor realmente retorna, identifica os clientes cujo tráfego é principalmente falhas e os bloqueia — decidido dentro do trabalhador NGINX, na própria solicitação, em poucos microssegundos. Sem sidecar. Sem log shipper. Sem camada de script. Apenas C compilado fazendo um trabalho excepcionalmente bem.

Ficha técnica

Gatilho Taxa de respostas de erro por cliente que você escolher (403/404 por padrão)
Ação Bloqueio temporário — uma proibição rígida por um período fixo, não um throttle
Ponto de decisão Fase de pré-acesso do NGINX, antes de qualquer manipulador ou upstream ser executado
Modelo de memória Bytes fixos por cliente, independente do limite → escala de botnet
Modo de frota Replicação de proibição opcional entre nós via Redis / Valkey
Durabilidade Capturas de saída opcionais preservam proibições ativas entre reinicializações
Pegada Um módulo autossuficiente; zero dependências em tempo de execução por padrão
Plataformas RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux

O problema que remove

Visitantes legítimos quase nunca geram uma explosão de erros. Abusadores geram pouco mais — essa assimetria é o jogo todo. Um scanner de vulnerabilidades percorrendo sua árvore é uma parede de 404s. Um bot cutucando endpoints de administrador é uma parede de 403s. Uma execução de força bruta é uma parede de falhas.

Limitadores de taxa tratam esse tráfego como qualquer outro: eles desaceleram todos pelo volume de solicitações e deixam o infrator entrar novamente no instante em que a pressão diminui. Abuse Guard faz o oposto. Ele ignora completamente o tráfego bem-comportado e reserva sua única resposta — uma proibição real, com tempo limitado — para clientes definidos por seus erros.

Use um limitador de taxa para moldar a carga. Use Abuse Guard para expulsar abusos.

Como uma proibição é decidida

Três partes móveis, todas dentro do trabalhador:

1 · Uma pontuação vazada, por cliente. Cada identidade de cliente carrega um único número pequeno na memória compartilhada. Cada erro correspondente adiciona a ele; a pontuação vaza continuamente a uma taxa de threshold ÷ interval por segundo. Uma explosão curta e aguda a empurra para o limite; um gotejamento lento nunca o faz. Crucialmente, essa pontuação é um registro de tamanho fixo não importa quão alto você defina o limite — assim, uma única zona rastreia confortavelmente as dezenas de milhares de endereços de origem distintos que uma botnet joga em você.

2 · Um prazo rígido. No momento em que a pontuação ultrapassa seu limite, o cliente ganha um timestamp blocked_until. Até então, ele simplesmente desaparece — cada solicitação é rejeitada na fase de pré-acesso, antes que o NGINX gaste um ciclo em roteamento, arquivos ou upstreams. A rejeição é o resultado mais barato possível.

3 · Uma recusa correta em termos de privacidade. Clientes banidos recebem 429 Too Many Requests (seu código de escolha) marcado para que nenhum cache compartilhado possa armazená-lo e servir a punição de um cliente a outro, com um Retry-After informando os clientes honestos quando retornar.

Identidades são incorporadas em um digest de tamanho fixo, então chavear em algo grande como $request_uri ou um cabeçalho custa exatamente a mesma quantidade de memória que chavear em um IP.

Ao vivo em menos de um minuto

Abuse Guard é enviado como um módulo pré-compilado e assinado do repositório GetPageSpeed — basta colocá-lo, sem necessidade de ferramenta de construção.

sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
sudo yum -y install nginx-module-abuse-guard

Conecte-o:

load_module modules/ngx_http_abuse_guard_module.so;

http {
    abuse_guard_zone zone=clients:10m;     # uma zona de memória compartilhada

    server {
        location / {
            abuse_guard zone=clients;      # aplique aqui
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

Esses padrões banem qualquer IP que retorna 100 403/404 respostas dentro de uma janela de 5 minutos, por uma hora. Aperte ou afrouxe cada número abaixo.

Configuração

Abuse Guard é composto por quatro diretivas. A primeira declara uma política; as demais a aplicam, isentam pessoas dela e (opcionalmente) a compartilham entre máquinas.

Declare uma política — abuse_guard_zone

Uma diretiva de nível http. Ela define uma zona de memória compartilhada e estabelece a política que a governa. Defina quantos ou quantos ajustes quiser — o nome e o tamanho da zona são a única coisa que você deve fornecer; valores padrão sensatos preenchem o resto (os valores mostrados abaixo são exatamente esses padrões).

abuse_guard_zone  zone=clients:10m             nome + tamanho (o único obrigatório)
                  key=$binary_remote_addr      quem é "um cliente"
                  statuses=403,404             quais respostas contam como erros
                  interval=300s                a janela de pontuação
                  threshold=100                erros nessa janela  banir
                  block=60m;                   quanto tempo a proibição dura

zone=clients:10m é a identidade e o orçamento da política: um nome que você referencia de abuse_guard, e o tamanho da memória compartilhada. Cerca de 10 MB rastreiam da ordem de cem mil clientes ativos.

Tudo o mais é ajuste opcional:

  • key — a expressão que define um único cliente. Qualquer variável NGINX; o padrão $binary_remote_addr chaveia no IP de origem. Uma solicitação cujo chave resulta em vazio é completamente ignorada (útil com um map, abaixo).
  • statuses — os códigos de resposta que contam como erros: códigos individuais, intervalos ou uma mistura, por exemplo, statuses=401,403,404,500-599. O padrão é 403,404.
  • interval — a janela em que a pontuação decai (padrão 300s). Uma explosão dentro dela ativa uma proibição; um gotejamento lento espalhado nunca acumula.
  • threshold — quantos erros dentro dessa janela ultrapassam o limite, até 1024 (padrão 100).
  • block — quanto tempo um cliente acionado permanece bloqueado (padrão 60m).
  • inactive — quanto tempo um cliente dormente permanece na memória antes de ser recuperado (padrão max(1h, interval, block); qualquer valor explícito deve ser pelo menos tão grande quanto interval e block).
  • redison para replicar as proibições dessa zona entre uma frota (veja abaixo); off por padrão.
  • persist — um caminho de arquivo onde as proibições ativas são despejadas na saída limpa do trabalhador e carregadas na inicialização.
  • persist_secret — em builds com suporte a snapshot assinado, uma chave hex que adiciona autenticação HMAC-SHA256 para que um arquivo adulterado seja rejeitado.

Por que 5xx é deixado de fora por padrão: um erro de servidor é geralmente culpa do seu lado, e contá-lo permitiria que um backend instável banisse visitantes inocentes. Adicione statuses=403,404,500-599 apenas quando você quiser deliberadamente agir sobre clientes que acionam erros de servidor.

Aplique-a — abuse_guard

Válido em blocos http, server e location, para que você possa proteger todo um site ou apenas os endpoints que atraem abusos. Nomeie a zona para ativá-la; escreva abuse_guard off; em um escopo aninhado para desativá-la.

location /wp-login.php {
    abuse_guard zone=clients status=429 log_level=warn;
}
  • zone — a zona (declarada acima) cuja política se aplica aqui.
  • status — o código que um cliente banido recebe, em qualquer lugar de 400599 (padrão 429).
  • dry_runon para observar sem impor: o veredicto é registrado, mas nenhuma proibição é escrita. Desligado por padrão.
  • log_level — quão alto registrar cada decisão: info, notice (padrão), warn ou error.

Implemente sem medo com dry_run=on. Ele registra cada proibição que emitiria sem tocar no estado, para que você possa calibrar limites em relação ao tráfego ao vivo — mesmo ao lado de uma localização que aplica a proibição na mesma zona — e depois ativá-la ao vivo.

Isente os bons — abuse_guard_allow

Contexto: http · server · location · repetível, herdado para baixo.

abuse_guard_allow 127.0.0.0/8;
abuse_guard_allow 10.0.0.0/8 192.168.0.0/16;

Os clientes listados nunca são contados e nunca são banidos. A correspondência é no verdadeiro endereço de conexão, então ele coopera com realip. Esta também é a forma como você protege crawlers de busca verificados: permita os intervalos publicados do Googlebot / Bingbot para que um bot que percorre URLs obsoletos (e acumulando 404s) nunca seja pego.

Compartilhe proibições entre a frota — abuse_guard_redis

Contexto: http

abuse_guard_redis host=10.0.0.5 password=… ;   # tls://host para TLS
abuse_guard_zone  zone=clients:10m redis=on;

Aponte cada nó para um Redis ou Valkey, ative redis=on, e uma proibição obtida em qualquer máquina se propaga para todas elas. Padrões: port=6379, db=0, prefix=ag_, timeout=100ms. Como isso permanece rápido é a próxima seção.

SELinux: em sistemas de aplicação (RHEL, Rocky, AlmaLinux) o kernel impede que o NGINX abra a conexão com o Redis até que você permita uma vez — setsebool -P httpd_can_network_connect 1. Pule isso e a replicação silenciosamente não faz nada enquanto a aplicação local continua normalmente.

Uma proibição, cada nó — sem atrasar uma única solicitação

Atrás de um balanceador de carga, uma proibição por servidor é teatro: o atacante simplesmente aterrissa em um nó diferente. Abuse Guard fecha essa lacuna sem nunca colocar o Redis no caminho da solicitação.

Cada nó decide localmente e conta localmente. No instante em que emite uma proibição, ele transmite esse único fato para o cluster e registra uma cópia durável. Cada outro nó a importa em milissegundos, e qualquer nó que estava offline reconcilia no momento em que se reconecta. Como a aplicação é sempre servida a partir do estado em memória de cada nó, a solicitação de um visitante nunca espera por uma viagem de ida e volta na rede — o único custo de clustering é que um atacante recém-banido é excluído em toda a frota um batimento cardíaco depois, em vez de instantaneamente.

O Redis aqui é um sino de alarme unidirecional, não um livro-razão compartilhado consultado por solicitação — então um Redis lento ou ausente nunca pode adicionar latência ao seu tráfego. Execute-o em uma rede privada e trate-o como privilegiado: qualquer coisa que possa escrever nele pode emitir proibições.

Proibições que sobrevivem a uma reinicialização

Aponte uma zona para um arquivo e as proibições ativas são despejadas quando o trabalhador sai limpo, depois restauradas na inicialização. Recargas e reinicializações ordenadas mantêm as proibições atuais sem executar um escritor de zona completo periódico. Uma falha abrupta de processo ou máquina pode perder proibições emitidas desde a última saída limpa; a aplicação ainda falha de forma aberta.

abuse_guard_zone zone=clients:10m
                 persist=/var/lib/nginx/abuse_guard/clients.state
                 persist_secret=00112233445566778899aabbccddeeff;

O snapshot compacto contém apenas digests de identidade e prazos de proibição. CRC32 detecta corrupção, e um renomear atômico mantém gravações parciais fora do caminho ativo. Builds com suporte a snapshot assinado podem autenticar adicionalmente com persist_secret. Mantenha o diretório legível apenas pelo usuário do trabalhador.

Veja tudo o que decide

Três variáveis expõem o veredicto do Abuse Guard aos seus logs e configuração:

Variável Valor
$abuse_guard_status BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN
$abuse_guard_count Erros atualmente atribuídos a este cliente.
$abuse_guard_blocked_until Tempo Unix em que a proibição é levantada, ou 0.
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

Chaveando atrás de um CDN ou proxy? Nunca confie em um X-Forwarded-For bruto. Deixe realip resolver o verdadeiro cliente primeiro, então chaveie em $binary_remote_addr:

set_real_ip_from 10.0.0.0/8;
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

Precisa de lógica de isenção por solicitação? Qualquer solicitação cuja key resulte em uma string vazia é ignorada — então um map permite que você, por exemplo, rastreie visitantes anônimos por IP enquanto deixa usuários autenticados intocados.

Projetado para ser confiável em produção

Abuse Guard é mantido a um padrão muito acima de "compila." Cada mudança passa pelo teste do AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, análise estática e fuzzing contínuo de seus parsers e formato em disco. Suas dependências opcionais — clustering e snapshots assinados — são de melhor esforço por design: se o Redis ou o disco se comportarem mal, a aplicação continua silenciosamente a partir da memória local. Seu tráfego nunca é mantido refém de uma dependência.

Obtenha o Abuse Guard

Abuse Guard é um módulo NGINX comercial da GetPageSpeed LLC, entregue com atualizações e suporte contínuos através de uma assinatura GetPageSpeed.

© GetPageSpeed LLC. Todos os direitos reservados.