Saltar a contenido

abuse-guard: Bloqueo automático de clientes abusivos según la tasa de respuestas de error

Instalación

Puede instalar este módulo en cualquier distribución basada en RHEL, incluyendo, entre otras:

  • RedHat Enterprise Linux 7, 8, 9 y 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 y 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

Habilite el módulo añadiendo lo siguiente al principio de /etc/nginx/nginx.conf:

load_module modules/ngx_http_abuse_guard_module.so;

Este documento describe nginx-module-abuse-guard v2.1.0 publicado el 3 de septiembre de 2026.


Su registro de errores es una confesión. Abuse Guard lo lee en tiempo real y expulsa a los abusadores.

Cada escáner, fuzzer y bot de relleno de credenciales deja la misma huella: una ráfaga de 404s buscando rutas ocultas, 403s probando puertas cerradas, solicitud fallida tras solicitud fallida. Abuse Guard observa los códigos de estado que su servidor realmente devuelve, identifica a los clientes cuyo tráfico es mayoritariamente fallido y los bloquea — decidido dentro del worker de NGINX, sobre la propia solicitud, en unos pocos microsegundos. Sin sidecar. Sin log shipper. Sin capa de scripting. Solo C compilado haciendo un trabajo excepcionalmente bien.

Ficha técnica

Disparador Tasa por cliente de respuestas de error que usted elija (403/404 por defecto)
Acción Bloqueo temporal — una prohibición firme durante una ventana fija, no una limitación
Punto de decisión Fase de preacceso de NGINX, antes de que se ejecute cualquier handler o upstream
Modelo de memoria Bytes fijos por cliente, independiente del umbral → escala a nivel de botnet
Modo flota Replicación opcional de prohibiciones entre nodos mediante Redis / Valkey
Durabilidad Instantáneas de salida opcionales que conservan las prohibiciones activas entre reinicios
Huella Un módulo autocontenido; cero dependencias en tiempo de ejecución por defecto
Plataformas RHEL / AlmaLinux / Rocky / CentOS Stream / Oracle / Amazon Linux
##

El problema que elimina

Los visitantes legítimos casi nunca generan una ráfaga de errores. Los abusadores generan poco más que eso — esa asimetría es todo el juego. Un escáner de vulnerabilidades que recorre su árbol es un muro de 404s. Un bot probando endpoints de administración es un muro de 403s. Un ataque de fuerza bruta es un muro de fallos.

Los limitadores de tasa tratan ese tráfico como cualquier otro: ralentizan a todos por volumen de solicitudes y dejan que el infractor vuelva a entrar en el mismo instante en que se calma. Abuse Guard hace lo contrario. Ignora por completo el tráfico bien comportado y reserva su única respuesta — una prohibición real y limitada en el tiempo — para clientes definidos por sus errores.

Use un limitador de tasa para modelar la carga. Use Abuse Guard para expulsar el abuso.

Cómo se decide una prohibición

Tres piezas móviles, todas dentro del worker:

1 · Una puntuación con fuga, por cliente. Cada identidad de cliente lleva un único número pequeño en memoria compartida. Cada error que coincide añade un punto por defecto, o el peso que usted asigne a ese estado; la puntuación se desvanece continuamente a umbral ÷ intervalo por segundo. Una ráfaga corta y aguda la empuja por encima del límite; un goteo lento nunca lo consigue. Fundamentalmente, esa puntuación es un único registro de tamaño fijo sin importar lo alto que establezca el umbral, por lo que una sola zona rastrea cómodamente las decenas de miles de direcciones de origen distintas que una botnet le lanza.

2 · Una fecha límite firme. En el momento en que la puntuación cruza su umbral, el cliente obtiene una marca de tiempo blocked_until. Hasta entonces simplemente desaparece — cada solicitud es rechazada en la fase de preacceso, antes de que NGINX gaste un ciclo en enrutamiento, archivos o upstreams. El rechazo es el resultado más barato posible.

3 · Una negativa correcta en cuanto a privacidad. Los clientes bloqueados reciben 429 Too Many Requests (el código que usted elija) etiquetado para que ninguna caché compartida pueda almacenarlo y servir el castigo de un cliente a otro, con un Retry-After que indica a los clientes honestos cuándo volver.

Las identidades se pliegan en un digest de tamaño fijo, por lo que usar como clave algo voluminoso como $request_uri o una cabecera cuesta exactamente la misma memoria que usar una IP.

En funcionamiento en menos de un minuto

Abuse Guard se distribuye como un módulo precompilado y firmado desde el repositorio GetPageSpeed — instálelo, sin necesidad de toolchain de compilación.

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

Conéctelo:

load_module modules/ngx_http_abuse_guard_module.so;

http {
    abuse_guard_zone zone=clients:10m;     # una zona de memoria compartida

    server {
        location / {
            abuse_guard zone=clients;      # aplicar aquí
        }
    }
}
sudo nginx -t && sudo systemctl reload nginx

Esos valores por defecto prohíben cualquier IP que devuelva 100 respuestas 403/404 en una ventana de 5 minutos, durante una hora. Ajuste cada número a continuación.

Configuración

Abuse Guard son cuatro directivas. La primera declara una política; el resto la aplican, eximen a personas de ella y (opcionalmente) la comparten entre máquinas.

Declarar una política — abuse_guard_zone

Una directiva a nivel de http. Reserva una zona de memoria compartida y establece la política que la gobierna. Configure tantos o tan pocos parámetros como desee — el nombre y el tamaño de la zona son lo único que debe proporcionar; los valores por defecto sensatos completan el resto (los valores mostrados a continuación son exactamente esos valores por defecto).

abuse_guard_zone  zone=clients:10m             nombre + tamaño (lo único imprescindible)
                  key=$binary_remote_addr      quién es "un cliente"
                  statuses=403,404             qué respuestas suman a la puntuación
                  interval=300s                la ventana de puntuación
                  threshold=100                puntuación en esa ventana  prohibición
                  block=60m;                   cuánto dura la prohibición

zone=clients:10m es la identidad y el presupuesto de la política: un nombre al que hace referencia abuse_guard, y el tamaño de la memoria compartida. Unos 10 MB rastrean del orden de cien mil clientes activos.

Todo lo demás es ajuste opcional:

  • key — la expresión que define un único cliente. Cualquier variable de NGINX; el valor por defecto $binary_remote_addr usa como clave la IP de origen. Una solicitud cuya clave resulta vacía se omite por completo (útil con un map, más abajo).
  • statuses — las respuestas que suman a la puntuación. Un código o rango simple tiene peso 1, conservando la sintaxis original: statuses=403,404,500-599. Añada :weight para que una respuesta consuma más del mismo presupuesto, por ejemplo statuses=404,401:5,500-599:2. Los pesos son enteros del 1 al 1024 y un rango aplica su peso a cada estado que cubre. Repetir o superponer un estado con el mismo peso es inofensivo; pesos conflictivos hacen fallar nginx -t. El valor por defecto sigue siendo 403,404.
  • interval — la ventana en la que la puntuación decae (por defecto 300s). Una ráfaga dentro de ella activa una prohibición; un goteo lento distribuido en un periodo más amplio nunca se acumula.
  • threshold — cuántos puntos de puntuación dentro de esa ventana cruzan el límite, hasta 1024 (por defecto 100). Una respuesta pesada puede consumir el presupuesto restante y activar una prohibición inmediatamente.
  • block — cuánto tiempo permanece bloqueado un cliente que ha activado la prohibición (por defecto 60m).
  • inactive — cuánto tiempo permanece un cliente inactivo en memoria antes de ser reclamado (por defecto max(1h, interval, block); cualquier valor explícito debe ser al menos tan grande como tanto interval como block).
  • redison para replicar las prohibiciones de esta zona en una flota (ver más abajo); off por defecto.
  • persist — una ruta de archivo donde las prohibiciones activas se vuelcan en la salida limpia del worker y se cargan al inicio.
  • persist_secret — en compilaciones con soporte de instantáneas firmadas, una clave hexadecimal que añade autenticación HMAC-SHA256 para que un archivo manipulado sea rechazado.

Por qué 5xx queda excluido por defecto: un error de servidor suele ser culpa de su lado, y contarlo permitiría que un backend con fallos intermitentes consiguiera que visitantes inocentes fueran bloqueados. Añada statuses=403,404,500-599 solo cuando quiera deliberadamente actuar sobre clientes que provocan errores de servidor.

Aplicarla — abuse_guard

Válida en bloques http, server y location, por lo que puede proteger un sitio completo o solo los endpoints que atraen abuso. Nombre la zona para activarla; escriba abuse_guard off; en un ámbito anidado para desactivarla.

location /wp-login.php {
    abuse_guard zone=clients status=429 log_level=warn;
}
  • zone — la zona (declarada arriba) cuya política se aplica aquí.
  • status — el código que recibe un cliente bloqueado, en cualquier lugar de 400599 (por defecto 429).
  • dry_runon para observar sin aplicar: el veredicto se registra pero no se escribe ninguna prohibición. Desactivado por defecto.
  • log_level — con qué nivel se registra cada decisión: info, notice (por defecto), warn o error.

Despliegue sin miedo con dry_run=on. Registra cada prohibición que emitiría sin tocar el estado, para que pueda calibrar los umbrales contra el tráfico real — incluso junto a una location que aplica en la misma zona — y luego actívelo en producción.

Eximir a los buenos — abuse_guard_allow

Contexto: http · server · location · repetible, heredado hacia abajo.

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

Los clientes listados nunca se cuentan ni se prohíben. La coincidencia se realiza sobre la dirección de conexión real, por lo que coopera con realip. Esta es también la forma de proteger rastreadores de búsqueda verificados: permita los rangos publicados de Googlebot / Bingbot para que un bot que recorre URLs obsoletas (y acumulando 404s) nunca sea atrapado.

Compartir prohibiciones en la flota — 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;

Apunte cada nodo a un único Redis o Valkey, active redis=on, y una prohibición obtenida en cualquier máquina se propaga a todas ellas. Valores por defecto: port=6379, db=0, prefix=ag_, timeout=100ms. Cómo se mantiene rápido es la siguiente sección.

SELinux: en sistemas con enforcing (RHEL, Rocky, AlmaLinux) el kernel impide que NGINX abra la conexión a Redis hasta que lo permita una vez — setsebool -P httpd_can_network_connect 1. Si omite esto, la replicación no hará nada silenciosamente mientras la aplicación local continúa con normalidad.

Una prohibición, cada nodo — sin ralentizar una sola solicitud

Detrás de un balanceador de carga, una prohibición por servidor es un teatro: el atacante simplemente aterriza en un nodo diferente. Abuse Guard cierra esa brecha sin poner nunca a Redis en la ruta de la solicitud.

Cada nodo decide localmente y cuenta localmente. En el instante en que emite una prohibición, transmite ese único hecho al clúster y registra una copia duradera. Cada otro nodo lo importa en milisegundos, y cualquier nodo que estaba sin conexión se reconcilia en el momento en que se reconecta. Debido a que la aplicación siempre se sirve desde el estado en memoria de cada nodo, la solicitud de un visitante nunca espera un viaje de ida y vuelta por la red — el único coste del agrupamiento es que un atacante recién prohibido queda excluido en toda la flota un latido después en lugar de instantáneamente.

Redis aquí es una campana de alarma unidireccional, no un libro de contabilidad compartido consultado por solicitud — por lo que un Redis lento o ausente nunca puede añadir latencia a su tráfico. Ejecútelo en una red privada y trátelo como privilegiado: cualquier cosa que pueda escribir en él puede emitir prohibiciones.

Prohibiciones que sobreviven a un reinicio

Apunte una zona a un archivo y las prohibiciones activas se vuelcan cuando el worker sale limpiamente, y luego se restauran al inicio. Las recargas y los reinicios ordenados mantienen las prohibiciones actuales sin ejecutar un escritor periódico de toda la zona. Un fallo abrupto del proceso o de la máquina puede perder prohibiciones emitidas desde la última salida limpia; la aplicación sigue fallando en abierto.

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

La instantánea compacta contiene solo digests de identidad y fechas límite de prohibición. CRC32 detecta corrupción, y un rename atómico mantiene las escrituras parciales fuera de la ruta activa. Las compilaciones con soporte de instantáneas firmadas pueden además autenticarla con persist_secret. Mantenga el directorio legible solo por el usuario del worker.

Vea todo lo que decide

Tres variables exponen el veredicto de Abuse Guard a sus registros y configuración:

Variable Valor
$abuse_guard_status BYPASSED · PASSED · COUNTED · BLOCKED · DRY_RUN
$abuse_guard_count Puntuación ponderada actual, redondeada a un punto entero.
$abuse_guard_blocked_until Tiempo Unix en que se levanta la prohibición, o 0.
log_format guard '$remote_addr "$request" $status '
                 'guard=$abuse_guard_status count=$abuse_guard_count';

¿Usando claves detrás de una CDN o proxy? Nunca confíe en un X-Forwarded-For crudo. Deje que realip resuelva primero el cliente real, y luego use como clave $binary_remote_addr:

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

¿Necesita lógica de exención por solicitud? Cualquier solicitud cuya key se resuelva a una cadena vacía se ignora — por lo que un map le permite, por ejemplo, rastrear visitantes anónimos por IP mientras deja intactos a los usuarios autenticados.

Diseñado para ser confiable en producción

Abuse Guard se mantiene en un estándar muy por encima de "compila". Cada cambio pasa por el calvario de AddressSanitizer, UndefinedBehaviorSanitizer, Valgrind, análisis estático y fuzzing continuo de sus analizadores y formato en disco. Sus dependencias opcionales — agrupamiento e instantáneas firmadas — son de mejor esfuerzo por diseño: si Redis o el disco se comportan mal, la aplicación continúa silenciosamente desde la memoria local. Su tráfico nunca es rehén de una dependencia.

Obtenga Abuse Guard

Abuse Guard es un módulo comercial de NGINX de GetPageSpeed LLC, entregado con actualizaciones continuas y soporte a través de una suscripción a GetPageSpeed.

© GetPageSpeed LLC. Todos los derechos reservados.