BLOG | NGINX

Listas de denegación de IP dinámicas con NGINX Plus y fail2ban

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Liam Crilly
Liam Crilly
Publicado el 19 de septiembre de 2017
Foto: Arnold Reinhold – Trabajo propio, CC BY‑SA 3.0

Puede que no te des cuenta, pero tu sitio web está bajo amenaza constante. Si ejecuta WordPress, los bots están intentando enviarle spam. Si tiene una página de inicio de sesión, hay ataques de fuerza bruta contra contraseñas. También puedes considerar a las arañas de los motores de búsqueda como visitantes no deseados.

Defender su sitio de actividades no deseadas, sospechosas y maliciosas no es una tarea fácil. Los firewalls de aplicação web, como NGINX App Protect y los módulos certificados NGINX Plus disponibles a través de nuestros socios, son herramientas efectivas y deben considerarse como parte de su pila de seguridad. En la mayoría de los entornos, nunca existe demasiada seguridad, y un enfoque de múltiples capas es invariablemente el más eficaz.

En esta publicación de blog, analizaremos el uso de fail2ban como otra capa de la pila de web security . Fail2ban es un sistema de detección de intrusiones (IDS) que monitorea continuamente los archivos de registro para detectar actividad sospechosa y luego toma una o más acciones preconfiguradas. Normalmente, fail2ban monitorea los intentos fallidos de inicio de sesión y luego bloquea (prohíbe) la dirección IP infractora durante un período de tiempo. Esta es una defensa simple pero efectiva contra ataques de fuerza bruta a contraseñas.

En NGINX Plus R13, introdujimos un almacén de clave-valor nativo y una nueva API de NGINX Plus. Esto permite una amplia gama de soluciones de configuración dinámica, en las que la configuración y el comportamiento de NGINX Plus pueden controlarse mediante un sistema externo. En esta publicación de blog, también mostraremos cómo se puede usar fail2ban para reconfigurar automáticamente NGINX Plus para ignorar las solicitudes de direcciones IP que han causado múltiples eventos de autenticación fallidos.

Editor: en NGINX Plus R16 y versiones posteriores, los almacenes de valores clave se pueden sincronizar en todas las instancias de NGINX Plus en un clúster. (El uso compartido de estados en un clúster también está disponible para otras funciones de NGINX Plus). Para obtener más detalles, consulte nuestro blog y la Guía de administración de NGINX Plus .

Uso de un almacén de clave-valor para listas de denegación de IP

El almacén de clave-valor NGINX Plus es un almacén nativo en memoria con tres características principales:

  1. Los pares clave-valor se representan como objetos JSON
  2. Los pares clave-valor se gestionan completamente a través de una API
  3. Los valores están disponibles para NGINX Plus como variables de configuración regulares

El almacén de valores clave se define mediante la creación de una zona de memoria compartida denominada mediante la directiva keyval_zone . Este almacén de valores clave se puede rellenar con un conjunto inicial de valores mediante el método HTTP POST para enviar un objeto JSON a la API. La directiva keyval define la variable existente que se usará como clave de búsqueda ( $remote_addr en el ejemplo) y el nombre de una nueva variable ( $num_failures ) que se evaluará a partir del valor correspondiente de esa clave.

Configuración y gestión del almacén de clave-valor de NGINX Plus

La API se habilita designando un bloque de ubicación como punto final de la API NGINX Plus.


servidor {
escuchar 1111;
permitir 127.0.0.1; # Solo permitir acceso desde localhost,
negar todo; # y evitar el acceso remoto.

ubicación /api {
api write=on; # El punto final de la API NGINX Plus en modo de lectura/escritura
}
}
keyval_zone zona=lista de denegación:1M;
keyval $dirección_remota $num_fallos zona=lista_de_negación;

servidor {
escuchar 80;

ubicación / {
raíz /usr/share/nginx/html;
si ($num_fallos) {
devolver 403;
}
}
}

vim: sintaxis=nginx

Antes de agregarle pares clave-valor, una solicitud de los contenidos del almacén de lista negra devuelve un objeto JSON vacío.

$ curl http://localhost:1111/api/6/http/keyvals/denylist {}

Ahora es posible rellenar el almacén de clave-valor con un par clave-valor inicial utilizando el método HTTP POST (en forma del argumento -d del comando curl ) para enviar un nuevo objeto JSON. Es posible enviar por POST varios pares clave-valor a un almacén de clave-valor vacío y de manera individual a partir de entonces.

$ curl -iX POST -d '{"10.0.0.1":"1"}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 201 Creado ...

Un par clave-valor se elimina aplicando PATCH a la clave con un valor de null .

$ curl -iX PATCH -d '{"10.0.0.1":null}' http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Sin contenido ...

Todos los pares clave-valor se pueden eliminar del almacén de clave-valor enviando el método DELETE .

$ curl -iX DELETE http://localhost:1111/api/6/http/keyvals/denylist HTTP/1.1 204 Sin contenido ...

Ahora se puede configurar una implementación sencilla de lista de denegación de IP.


servidor {
escuchar 1111;
permitir 127.0.0.1; # Solo permitir acceso desde localhost,
negar todo; # y evitar el acceso remoto.

ubicación /api {
api write=on; # El punto final de la API NGINX Plus en modo de lectura/escritura
}
}
keyval_zone zona=lista de denegación:1M;
keyval $dirección_remota $num_fallos zona=lista_de_negación;

servidor {
escuchar 80;

ubicación / {
raíz /usr/share/nginx/html;
si ($num_fallos) {
devolver 403;
}
}
}

vim: sintaxis=nginx

Este fragmento de configuración configura el puerto 80 como servidor web. La línea 18 evalúa la variable $num_failures como la parte del valor del par clave-valor en la zona de memoria compartida de la lista de bloqueados que coincide con la clave que corresponde a la variable $remote_addr (dirección IP del cliente). Este proceso de evaluación de $num_failures se expresa más claramente de forma secuencial:

  1. Pase el valor de $remote_addr al almacén de clave-valor de la lista de denegados
  2. Si $remote_addr es una coincidencia exacta para una clave, entonces obtenga el valor de ese par clave-valor
  3. Devuelve el valor como $num_failures

Y así, si la dirección IP del cliente ha sido CORREO-ed al almacén de clave-valor, entonces todas las solicitudes resultan en un HTTP 403 Prohibido error. La ventaja de este enfoque, en lugar de utilizar un bloque de mapas para el mismo propósito, es que la lista de direcciones IP rechazadas puede ser controlada por un sistema externo.

Uso de fail2ban para administrar dinámicamente la lista de direcciones IP denegadas

Como se mencionó anteriormente, fail2ban se usa comúnmente para detectar actividad sospechosa y/o maliciosa en archivos de registro y luego tomar medidas para proteger el sistema. La acción predeterminada es configurar iptables para descartar todos los paquetes que se originan en la dirección IP que se registró. Este enfoque, aunque eficaz para bloquear a un actor malicioso, proporciona una experiencia de usuario muy pobre para los usuarios genuinos, especialmente si han olvidado su contraseña. Para estos usuarios, parece como si el sitio web simplemente no estuviera disponible.

La siguiente configuración describe una acción fail2ban que envía la dirección IP infractora al almacén de clave-valor de lista negra de NGINX Plus. Luego, NGINX Plus muestra una página de error más útil y aplica simultáneamente un límite de tasa de solicitud a esa dirección IP para que, si las acciones son parte de un ataque, el ataque se neutralice de manera efectiva.

Suponemos una instalación predeterminada de fail2ban en el mismo host que NGINX Plus, con toda la configuración en el directorio /etc/fail2ban .

La siguiente acción fail2ban utiliza la API NGINX Plus para agregar y eliminar direcciones IP “prohibidas” dentro del almacén de clave-valor de la lista de bloqueados de la misma manera que nuestro ejemplo simple anterior. Colocamos el archivo nginx-plus-denylist.conf en el directorio /etc/fail2ban/action.d .


[Definición]
actionban = curl -s -o /dev/null -d '{"":""}' http://localhost:1111/api/6/http/keyvals/denylist
actionunban = curl -s -o /dev/null -X PATCH -d '{"":null}' http://localhost:1111/api/6/http/keyvals/denylist

La siguiente cárcel fail2ban habilita el filtro integrado que detecta intentos fallidos de inicio de sesión mediante el módulo de autenticación básica HTTP de NGINX y aplica la acción definida en nginx-plus-denylist.conf . Hay muchos otros filtros integrados disponibles y se pueden crear fácilmente para detectar actividad no deseada en los registros de acceso de NGINX.


[PREDETERMINADO]
Tiempo de prohibición = 120
Acción de prohibición = nginx-plus-denylist

[nginx-http-auth]
Habilitado = verdadero

El siguiente fragmento de configuración de NGINX Plus aplica la autenticación básica HTTP a la página predeterminada “Bienvenido a NGINX”. Colocamos el archivo password_site.conf en el directorio /etc/nginx/conf.d .


servidor {
escuchar 1111;
permitir 127.0.0.1; # Solo permitir acceso desde localhost,
negar todo; # y evitar el acceso remoto.

ubicación /api {
api write=on; # El punto final de la API NGINX Plus en modo de lectura/escritura
}
}

keyval_zone zona=lista de denegación:1M estado=lista de denegación.json;
keyval $dirección_remota $num_fallos zona=lista_de_negación;

límite_req_zona $dirección_remota_binaria zona=20permin:10M tasa=20r/m;

servidor {
escuchar 80;
raíz /usr/share/nginx/html;

ubicación / {
auth_basic "sitio cerrado";
archivo_de_usuario_básico_de_autenticación usuarios.htpasswd;

si ($num_fallos) {
reescribir ^.* /banned.html;
}
}

ubicación = /banned.html {
límite_req zona=20permin ráfaga=100;
}
}

vim: sintaxis=nginx

La línea 11 define keyval_zone como en denylist_keyval.conf anterior, pero con el agregado del parámetro state , que especifica un archivo donde se guarda el estado del almacén de clave-valor y, por lo tanto, persiste cuando NGINX Plus se detiene y se reinicia. El almacén de valores clave persiste durante las recargas de configuración regulares sin especificar un archivo de estado. (Las líneas 1 a 10 no se muestran, pero son las mismas que en denylist_keyval.conf ).

La línea 14 crea una zona de memoria compartida llamada 20permin y especifica una tasa de solicitud máxima de 20 solicitudes por minuto para cada dirección IP del cliente. Este límite de velocidad se aplica luego cuando fail2ban agrega una dirección IP a la lista de bloqueados (línea 30).

El bloque de servidor define un servidor web que escucha en el puerto predeterminado (80), donde todas las solicitudes coinciden con la ubicación / bloque (línea 20). La directiva raíz (línea 18) especifica dónde reside nuestro contenido web. Las líneas 21 y 22 especifican que se requiere autenticación básica HTTP para este sitio y que la base de datos de contraseñas de los usuarios autorizados se encuentra en el archivo users.htpasswd . La documentación de la directiva auth_basic_user_file describe el formato de ese archivo. Tenga en cuenta que esta configuración no está cifrada para fines de prueba y cualquier sitio web de producción que utilice autenticación básica HTTP debe usar SSL/TLS para la seguridad del transporte.

Cuando la dirección IP del cliente ha sido incluida en la lista negra (líneas 24 a 26), en lugar de devolver el HTTP403 código de error, reescribimos la solicitud para que sea /banned.html que luego se procesa en el bloque de ubicación que coincide exactamente con esa URI (línea 29). Esto devuelve una página web estática que explica que la dirección IP del usuario ha sido bloqueada debido a fallas de inicio de sesión excesivas. También aplica un límite de velocidad restrictivo (línea 30) que evita que un cliente malicioso consuma innecesariamente recursos del sistema.

Página que ven los usuarios cuando su dirección IP está en la lista negra

(El HTML de esta página web de muestra está disponible como baneado.html en el repositorio de GitHub para esta publicación).

Podemos simular sucesivos intentos fallidos de inicio de sesión y la actividad fail2ban correspondiente de la siguiente manera.

$ curl -i http://admin:contraseña@www.ejemplo.com/HTTP/1.1 401 No autorizado...
$ curl -i http://admin:admin@www.ejemplo.com/
HTTP/1.1 401 No autorizado...
$ curl -i http://admin:pass1234@www.example.com/
HTTP/1.1 401 No autorizado...
$ curl -i http://admin:déjameentrar@www.ejemplo.com/
HTTP/1.1 401 No autorizado...
$ curl -i http://admin:fred@www.ejemplo.com/
HTTP/1.1 401 No autorizado...
$ rizo http://admin:P@ssw0rd@www.ejemplo.com/
<!DOCTYPE html>
<html>
<head>
<title>Prohibido</title>
...
$ cola -f /var/log/fail2ban.log
15/09/2017 13:55:18,903 fail2ban.filter [28498]: INFORMACIÓN [nginx-http-auth] Se encontró 172.16.52.1 2017-09-15 13:55:28,836 fail2ban.filter [28498]: INFORMACIÓN [nginx-http-auth] Se encontró 172.16.52.1 2017-09-15 13:57:49,228 fail2ban.filter [28498]: INFORMACIÓN [nginx-http-auth] Se encontró 172.16.52.1 2017-09-15 13:57:50,286 fail2ban.filter [28498]: INFORMACIÓN [nginx-http-auth] Se encontró 172.16.52.1 2017-09-15 13:57:52,015 fail2ban.filter [28498]: INFORMACIÓN [nginx-http-auth] Se encontró 172.16.52.1 2017-09-15 13:57:52,088 fail2ban.actions [28498]: AVISO [nginx-http-auth] Prohibición 172.16.52.1 2017-09-15 13:59:52,379 fail2ban.actions [28498]: AVISO [nginx-http-auth] Desbanear 172.16.52.1

Esta solución de lista negra de IP dinámica ahora puede ejecutarse sin necesidad de realizar más cambios de configuración. Fail2ban supervisa los archivos de registro de NGINX y añade las direcciones IP bloqueadas al almacén de clave-valor de NGINX Plus mediante la API. Después de 120 segundos (el tiempo de bloqueo configurado en jail.local ), la dirección IP infractora se elimina de la lista de bloqueados, utilizando nuevamente la API de NGINX Plus, y se aceptan nuevamente los intentos de inicio de sesión desde esa dirección.

La API NGINX Plus y el almacén de clave-valor hacen posible este tipo de integración. Ahora se pueden lograr soluciones de configuración avanzadas sin necesidad de construir archivos de configuración NGINX Plus ni realizar recargas. Nos encantaría saber cómo utiliza estas funciones para crear sus propias soluciones de configuración dinámica. Añade un comentario a continuación.

Para probar NGINX Plus, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.