--- title: "Cómo configurar el WAF NAXSI con Nginx en Ubuntu 24.04" description: "Compila NAXSI como módulo dinámico de Nginx en Ubuntu 24.04, activa las reglas base, ajusta falsos positivos en modo aprendizaje y bloquea SQLi y XSS." category: "Seguridad de Red Avanzada" language: es source: https://cubepath.com/es/docs/seguridad-de-red-avanzada/firewall-de-aplicacion-web-con-naxsi updated: 2026-09-25 --- # Cómo configurar el WAF NAXSI con Nginx en Ubuntu 24.04 NAXSI (Nginx Anti XSS & SQL Injection) es un firewall de aplicaciones web (WAF) que funciona como módulo de Nginx. En lugar de depender de una base de firmas, puntúa cada petición según caracteres y palabras que no deberían aparecer en una URL o un formulario (`<`, `"`, `union`, `../`...) y la bloquea cuando la puntuación supera un umbral. Por eso bloquea mucho por defecto, y el trabajo del administrador es añadir excepciones (whitelists) para el tráfico legítimo de su aplicación. En este tutorial compilarás NAXSI como módulo dinámico para el Nginx de Ubuntu 24.04, cargarás las reglas base, protegerás un sitio, usarás el modo aprendizaje para detectar falsos positivos, escribirás whitelists y una regla propia, y comprobarás que los ataques se bloquean con un 403. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Nginx instalado desde los repositorios de Ubuntu y un sitio funcionando (en los ejemplos se usa el sitio por defecto en `/var/www/html`). - Unos 500 MB libres en disco para las fuentes y la compilación. > Nota: el proyecto original `nbs-system/naxsi` se archivó en 2023. Esta guía usa el fork mantenido por su último desarrollador activo, `wargio/naxsi`, que es el que recomienda la documentación actual. ## Paso 1: Instalar las dependencias de compilación Ubuntu no empaqueta NAXSI, así que hay que compilarlo contra el código fuente de la misma versión de Nginx que tienes instalada. Instala Nginx (si aún no lo tienes) y las herramientas de compilación: ```bash sudo apt update sudo apt install nginx build-essential libpcre2-dev zlib1g-dev wget ``` Comprueba la versión exacta de Nginx, porque el módulo solo se cargará si se compila contra ella: ```bash nginx -v ``` ```output nginx version: nginx/1.24.0 (Ubuntu) ``` El Nginx de Ubuntu está compilado con `--with-compat`, lo que permite cargar módulos dinámicos compilados aparte siempre que la versión coincida. ## Paso 2: Descargar NAXSI y las fuentes de Nginx Trabaja en un directorio temporal dentro de tu home: ```bash mkdir -p ~/naxsi-build && cd ~/naxsi-build ``` Descarga la última versión de NAXSI con sus dependencias incluidas (libinjection). Consulta la versión actual en la [página de releases](https://github.com/wargio/naxsi/releases); en el momento de escribir esta guía es la 1.7: ```bash NAXSI_VERSION=1.7 wget "https://github.com/wargio/naxsi/releases/download/${NAXSI_VERSION}/naxsi-${NAXSI_VERSION}-src-with-deps.tar.gz" mkdir -p naxsi tar -C naxsi -xzf "naxsi-${NAXSI_VERSION}-src-with-deps.tar.gz" ``` Descarga ahora el código fuente de Nginx de nginx.org con la misma versión que devolvió `nginx -v`. El siguiente comando la extrae automáticamente: ```bash NGINX_VERSION=$(nginx -v 2>&1 | grep -oP 'nginx/\K[0-9.]+') echo "$NGINX_VERSION" wget "https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" tar -xzf "nginx-${NGINX_VERSION}.tar.gz" ``` Verifica que tienes los dos árboles de código: ```bash ls ~/naxsi-build/naxsi ~/naxsi-build/nginx-*/ ``` Deberías ver `naxsi_src` y `naxsi_rules` en el primero, y `configure` y `src` en el segundo. ## Paso 3: Compilar el módulo dinámico Configura Nginx con `--with-compat` y añade NAXSI como módulo dinámico. Solo se compilan los módulos, no un Nginx nuevo: ```bash cd ~/naxsi-build/nginx-*/ ./configure --with-compat --add-dynamic-module=../naxsi/naxsi_src make modules ``` Durante `configure` puede aparecer `No package 'libinjection' found` seguido de `Using submodule libinjection`. Es normal: usa la copia de libinjection incluida en el tarball. Comprueba que el módulo se ha generado: ```bash ls -l objs/ngx_http_naxsi_module.so ``` ```output -rwxrwxr-x 1 your_user your_user 1392584 sep 25 10:12 objs/ngx_http_naxsi_module.so ``` ## Paso 4: Instalar el módulo y las reglas Copia el módulo al directorio de módulos de Nginx en Ubuntu: ```bash sudo install -m 0644 objs/ngx_http_naxsi_module.so /usr/lib/nginx/modules/ ``` Ubuntu carga los módulos a través de ficheros en `/etc/nginx/modules-enabled/`, que `nginx.conf` incluye al principio. Crea el fichero de carga siguiendo esa convención: ```bash echo 'load_module modules/ngx_http_naxsi_module.so;' | sudo tee /etc/nginx/modules-available/mod-http-naxsi.conf sudo ln -s /etc/nginx/modules-available/mod-http-naxsi.conf /etc/nginx/modules-enabled/50-mod-http-naxsi.conf ``` Copia las reglas de NAXSI a `/etc/nginx/naxsi/`: ```bash sudo mkdir -p /etc/nginx/naxsi sudo cp -r ~/naxsi-build/naxsi/naxsi_rules/* /etc/nginx/naxsi/ ls /etc/nginx/naxsi ``` ```output blocking naxsi_core.rules whitelists ``` `naxsi_core.rules` contiene las reglas genéricas (SQLi, XSS, RFI, traversal, subidas). `blocking/` tiene reglas adicionales por categoría y `whitelists/` excepciones ya preparadas para aplicaciones conocidas como WordPress o Drupal. ## Paso 5: Cargar las reglas base Las reglas globales se declaran con `MainRule` y deben estar en el contexto `http`. En Ubuntu, `nginx.conf` incluye `/etc/nginx/conf.d/*.conf` dentro de `http`, así que crea ahí un fichero: ```bash sudo nano /etc/nginx/conf.d/naxsi.conf ``` ```nginx # Reglas globales de NAXSI (contexto http) include /etc/nginx/naxsi/naxsi_core.rules; ``` Crea también un fragmento reutilizable con las directivas que se aplican a cada `location` protegida. Así no repites las mismas líneas en cada sitio: ```bash sudo nano /etc/nginx/naxsi/location.rules ``` ```nginx SecRulesEnabled; LearningMode; LibInjectionSql; LibInjectionXss; DeniedUrl "/RequestDenied"; CheckRule "$SQL >= 8" BLOCK; CheckRule "$XSS >= 8" BLOCK; CheckRule "$RFI >= 8" BLOCK; CheckRule "$UWA >= 8" BLOCK; CheckRule "$EVADE >= 8" BLOCK; CheckRule "$UPLOAD >= 5" BLOCK; CheckRule "$TRAVERSAL >= 5" BLOCK; CheckRule "$LIBINJECTION_SQL >= 8" BLOCK; CheckRule "$LIBINJECTION_XSS >= 8" BLOCK; ``` Qué hace cada directiva: - `SecRulesEnabled` activa NAXSI en la `location`. Sin ella el módulo no hace nada. - `LearningMode` convierte las acciones `BLOCK` en `LOG`: registra lo que habría bloqueado sin cortar tráfico. Empezarás así y lo quitarás en el paso 8. - `LibInjectionSql` y `LibInjectionXss` activan la detección de libinjection, que suma puntos a `$LIBINJECTION_SQL` y `$LIBINJECTION_XSS`. - `DeniedUrl` es la redirección interna a la que se envía una petición bloqueada. - Los `CheckRule` son obligatorios con las reglas base: definen el umbral de cada puntuación. > Nota: las reglas internas (id inferior a 1000, como peticiones malformadas o JSON inválido) bloquean incluso en modo aprendizaje. ## Paso 6: Proteger un sitio Edita el bloque `server` de tu sitio. En este ejemplo, el sitio por defecto: ```bash sudo nano /etc/nginx/sites-available/default ``` Deja el bloque `server` como este (ajusta `server_name` y `root` a los tuyos): ```nginx server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm; server_name your_domain; location / { include /etc/nginx/naxsi/location.rules; try_files $uri $uri/ =404; } location /RequestDenied { internal; return 403; } } ``` La `location /RequestDenied` es `internal` para que nadie pueda pedirla directamente y deducir que hay un WAF delante. Si tu sitio es un proxy inverso, pon el `include` dentro de la `location` que contiene el `proxy_pass`. Valida la configuración y recarga Nginx: ```bash sudo nginx -t sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Lanza una petición con una comilla doble en un parámetro, algo que la regla 1001 puntúa como SQLi y XSS: ```bash curl -s -o /dev/null -w '%{http_code}\n' 'http://localhost/?q="test' ``` ```output 200 ``` Devuelve 200 porque estás en modo aprendizaje, pero la petición queda registrada en el log de errores de Nginx: ```bash sudo grep NAXSI_FMT /var/log/nginx/error.log | tail -n 1 ``` ```output 2026/09/25 10:30:12 [error] 12345#12345: *7 NAXSI_FMT: ip=127.0.0.1&server=localhost&uri=%2F&config=learning&rid=6c1f...&cscore0=$SQL&score0=8&cscore1=$XSS&score1=8&zone0=ARGS&id0=1001&var_name0=q, client: 127.0.0.1, server: your_domain, request: "GET /?q=%22test HTTP/1.1", host: "localhost" ``` Los campos importantes son `config=learning` (no se bloqueó), `id0` (regla que saltó), `zone0` (dónde: `ARGS`, `BODY`, `URL`, `HEADERS`) y `var_name0` (el parámetro). ## Paso 7: Detectar falsos positivos y escribir whitelists Deja el modo aprendizaje activo mientras usas la aplicación de forma normal: navega, envía formularios, inicia sesión, usa el buscador. Si puedes, déjalo así unos días con tráfico real. Después agrupa los eventos por zona, regla y parámetro para ver qué se repite: ```bash sudo grep -oE 'zone0=[^&]*&id0=[0-9]+&var_name0=[^&,]*' /var/log/nginx/error.log | sort | uniq -c | sort -rn | head -n 20 ``` ```output 42 zone0=ARGS&id0=1001&var_name0=q 17 zone0=BODY&id0=1302&var_name0=comment 3 zone0=URL&id0=1000&var_name0= ``` Cada línea frecuente de tráfico legítimo es candidata a una whitelist. Revisa también las URIs completas en el log antes de decidir: una whitelist mal acotada abre un hueco real. Las whitelists usan la directiva `BasicRule wl:` con una zona de coincidencia (`mz:`) lo más estrecha posible. Crea un fichero para las del sitio: ```bash sudo nano /etc/nginx/naxsi/whitelist-your_domain.rules ``` ```nginx # El buscador acepta comillas en el parámetro q, solo en /search BasicRule wl:1001 "mz:$URL:/search|$ARGS_VAR:q"; # El campo comment del formulario puede contener < y > BasicRule wl:1302,1303 "mz:$URL:/contact|$BODY_VAR:comment"; ``` Algunos ejemplos de zonas de coincidencia: | Zona | Significado | |---|---| | `$ARGS_VAR:q` | El parámetro `q` de la query string | | `$BODY_VAR:comment` | El campo `comment` de un POST | | `$URL:/search` | Solo en esa URL exacta | | `$HEADERS_VAR:Cookie` | La cabecera Cookie | Combinar `$URL` con otra zona mediante `|` aplica ambas condiciones a la vez, que es lo recomendable. Incluye el fichero dentro de la `location` protegida, justo después del `include` de `location.rules`: ```nginx location / { include /etc/nginx/naxsi/location.rules; include /etc/nginx/naxsi/whitelist-your_domain.rules; try_files $uri $uri/ =404; } ``` Si usas WordPress, Drupal u otra aplicación conocida, empieza por la whitelist correspondiente de `/etc/nginx/naxsi/whitelists/` en lugar de escribirla de cero. Valida y recarga: ```bash sudo nginx -t && sudo systemctl reload nginx ``` ## Paso 8: Añadir una regla propia Las reglas propias se escriben con `MainRule` (globales) o `BasicRule` (por `location`). Usa identificadores altos para no chocar con las reglas incluidas. Esta regla bloquea peticiones cuyo User-Agent contiene `sqlmap`: ```bash sudo nano /etc/nginx/naxsi/custom.rules ``` ```nginx MainRule id:90001 "s:$UWA:8" "str:sqlmap" "mz:$HEADERS_VAR:User-Agent" "msg:sqlmap en el user-agent"; ``` - `id` es el identificador de la regla (usa valores de 5 o más cifras para las tuyas). - `s:$UWA:8` suma 8 puntos a la puntuación `$UWA` (Unwanted Access), que ya tiene su `CheckRule`. - `str:` busca una cadena literal; `rx:` aceptaría una expresión regular. - `mz:` indica dónde buscar. Inclúyela en el contexto `http`, junto a las reglas base: ```bash sudo nano /etc/nginx/conf.d/naxsi.conf ``` ```nginx # Reglas globales de NAXSI (contexto http) include /etc/nginx/naxsi/naxsi_core.rules; include /etc/nginx/naxsi/custom.rules; ``` ## Paso 9: Pasar a modo bloqueo Cuando el log ya no muestre eventos de tráfico legítimo, desactiva el modo aprendizaje comentando la línea en `location.rules`: ```bash sudo nano /etc/nginx/naxsi/location.rules ``` ```nginx SecRulesEnabled; # LearningMode; LibInjectionSql; LibInjectionXss; ``` Valida y recarga: ```bash sudo nginx -t && sudo systemctl reload nginx ``` Comprueba que un intento de XSS, uno de SQLi y la regla propia se bloquean: ```bash curl -s -o /dev/null -w '%{http_code}\n' 'http://localhost/?q=' curl -s -o /dev/null -w '%{http_code}\n' "http://localhost/?id=1'+union+select+password+from+users--" curl -s -o /dev/null -w '%{http_code}\n' -A 'sqlmap/1.8' http://localhost/ ``` ```output 403 403 403 ``` Y que el tráfico normal sigue pasando: ```bash curl -s -o /dev/null -w '%{http_code}\n' 'http://localhost/?q=cubepath' ``` ```output 200 ``` En el log, los eventos bloqueados aparecen ahora con `config=block`: ```bash sudo grep -c 'config=block' /var/log/nginx/error.log ``` Sigue revisando el log durante los primeros días en modo bloqueo. Cualquier 403 legítimo que reporten tus usuarios se resuelve igual que en el paso 7: identificar regla, zona y parámetro, y añadir una whitelist acotada. ## Mantener el módulo tras actualizar Nginx El módulo está compilado para una versión concreta de Nginx. Las actualizaciones de seguridad de Ubuntu mantienen la versión 1.24.0, pero si en algún momento cambia la versión upstream (por ejemplo, al actualizar a otra versión de Ubuntu o usar el repositorio de nginx.org), Nginx se negará a arrancar hasta que recompiles. Después de actualizar, comprueba siempre: ```bash nginx -v sudo nginx -t ``` Si la versión ha cambiado, repite los pasos 2 a 4 con la nueva versión antes de reiniciar Nginx. ## Solución de problemas **`unknown directive "SecRulesEnabled"`**: el módulo no está cargado. Comprueba que existe `/etc/nginx/modules-enabled/50-mod-http-naxsi.conf` y que apunta a un fichero con la línea `load_module`. **`module "/usr/lib/nginx/modules/ngx_http_naxsi_module.so" version 1024000 instead of 1026000`**: el módulo se compiló para otra versión de Nginx. Recompílalo con las fuentes de la versión que muestra `nginx -v`. **`module ... is not binary compatible`**: falta `--with-compat` en el `./configure` del paso 3. Vuelve a ejecutar `configure` y `make modules`. **Peticiones POST con JSON bloqueadas por la regla 15 u 11**: NAXSI valida el cuerpo según el `Content-Type`. Asegúrate de que el cliente envía `Content-Type: application/json` con un JSON válido; si una ruta concreta usa un formato que NAXSI no entiende, crea una whitelist acotada a esa `$URL`. **Líneas de log cortadas**: Nginx limita la longitud de cada línea del log de errores, así que una petición con muchas coincidencias puede aparecer truncada. Filtra por el campo `rid` para agrupar los eventos de la misma petición. ## Conclusión Tienes NAXSI compilado como módulo dinámico para el Nginx de Ubuntu 24.04, con las reglas base y libinjection activos, whitelists acotadas para tu aplicación y una regla propia, todo en modo bloqueo. Como siguientes pasos puedes: - Añadir HTTPS al sitio con Let's Encrypt y Certbot, manteniendo las mismas directivas en el bloque `server` de 443. - Enviar `/var/log/nginx/error.log` a tu sistema de logs centralizado y alertar sobre picos de `config=block`. - Complementar el WAF con limitación de peticiones (`limit_req`) de Nginx y Fail2ban para bloquear por IP a los clientes que acumulan 403.