WAF (ModSecurity)

Monitorear eventos de WAF, analizar ataques, ajustar reglas y listar IPs permitidas para OWASP ModSecurity CRS a través de Docker

Documentación

WAF MCP Server

Un servidor MCP (Model Context Protocol) para gestionar OWASP ModSecurity CRS mediante Docker. Proporciona a asistentes de IA como Claude acceso directo a la monitorización, análisis y configuración del WAF a través de un pipeline estructurado de exploración descendente.

Diseñado para Claude Code pero funciona con cualquier cliente compatible con MCP.

Por qué

Los servicios proxy de LLM (LiteLLM, OpenRouter, etc.) se sitúan detrás de WAFs que generan enormes cantidades de falsos positivos: los prompts contienen código, SQL, HTML y comandos de shell que activan todas las reglas de inspección de contenido existentes. Gestionar estos WAFs requiere monitorización constante, ajuste de exclusiones e investigación de eventos.

Este servidor MCP permite que un asistente de IA realice ese trabajo directamente:

  1. Resumen — ver eventos totales, IPs únicas y reglas activas de un vistazo
  2. Exploración descendente — filtrar eventos por IP o regla, inspeccionar los datos coincidentes
  3. Actuar — deshabilitar reglas, incluir IPs en lista blanca, cambiar el modo del motor, todo sin salir de la conversación

Herramientas

Análisis (pipeline de exploración descendente)

HerramientaDescripción
waf_overviewPanel: eventos totales, IPs/reglas únicas, eventos de la última hora
waf_top_ipsIPs principales por número de eventos con enriquecimiento geográfico (ipinfo.io)
waf_top_rulesReglas más activadas con severidad y descripción
waf_fp_candidatesReglas que se activaron en respuestas HTTP 2xx (candidatas a falsos positivos)
waf_events_by_ipEventos filtrados por IP de origen
waf_events_by_ruleEventos filtrados por ID de regla
waf_event_detailEvento completo: cabeceras, cuerpo de la solicitud, todas las coincidencias de reglas con los datos coincidentes

Acciones

HerramientaDescripción
waf_statusEstado del contenedor, modo del motor, reglas cargadas, nivel de paranoia
waf_set_engineCambiar entre On, Off, DetectionOnly
waf_set_paranoiaEstablecer el nivel de paranoia del CRS (1–4)
waf_disable_ruleDeshabilitar una regla por ID (añade SecRuleRemoveById a las exclusiones)
waf_enable_ruleVolver a habilitar una regla previamente deshabilitada
waf_allow_ipIncluir una IP en la lista blanca (omitir el WAF por completo)
waf_deny_ipEliminar una IP de la lista blanca
waf_testEjecutar suite de pruebas: detección de escáneres, SQLi, XSS, path traversal

Parámetros comunes

since — Todas las herramientas de análisis aceptan un parámetro since para controlar la ventana de tiempo. El valor predeterminado es "24h". Admite la sintaxis de duración de Docker: "1h", "24h", "7d", "30m". Los días se convierten automáticamente a horas (el --since de Docker no admite el sufijo d de forma nativa).

waf_overview(since: "7d")        # last 7 days
waf_events_by_ip(ip: "1.2.3.4", since: "1h")  # last hour

verbose — waf_events_by_ip, waf_events_by_rule y waf_event_detail aceptan verbose: true. De forma predeterminada, matchedData y requestBody se truncan para mantener las respuestas dentro de los límites de contexto:

CampoPredeterminadoDetallado
matchedData (por regla)150–200 caracteres4000 caracteres
requestBody500 caracteres8000 caracteres

Requisitos previos

  • Docker con un contenedor owasp/modsecurity-crs en ejecución
  • Docker Compose gestionando el contenedor de ModSecurity
  • Node.js 18+
  • ModSecurity configurado con registro de auditoría JSON Serial (SecAuditLogFormat JSON)

Instalación

git clone https://github.com/KratosUAE/waf_mcp.git
cd waf_mcp
npm install
npm run build

Configuración

Variables de entorno

VariableRequeridaPredeterminadoDescripción
WAF_COMPOSE_DIRSí—Ruta al directorio que contiene docker-compose.yml
WAF_DOMAINNohttps://localhostDominio para solicitudes de prueba del WAF
WAF_LOGS_SINCENo24hVentana de tiempo predeterminada para consultas de registros
WAF_CONTAINER_PATTERNNomodsecurityPatrón grep para encontrar el contenedor de ModSecurity
WAF_EXCLUSIONS_FILENomodsecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confRuta al archivo de exclusiones del CRS (relativa al directorio de compose)
WAF_COMPOSE_FILENodocker-compose.ymlNombre del archivo de Docker Compose
IPINFO_TOKENNo—Token de ipinfo.io para geolocalización de IPs
WAF_DEBUGNo—Establecer cualquier valor para habilitar el registro de depuración

Conectar con Claude Code

claude mcp add --transport stdio --scope user \
  -e WAF_COMPOSE_DIR=/path/to/your/compose/dir \
  -e WAF_DOMAIN=https://your-domain.com \
  waf -- node /path/to/waf_mcp/dist/index.js

O añadir manualmente a ~/.claude.json:

{
  "mcpServers": {
    "waf": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/waf_mcp/dist/index.js"],
      "env": {
        "WAF_COMPOSE_DIR": "/path/to/your/compose/dir",
        "WAF_DOMAIN": "https://your-domain.com"
      }
    }
  }
}

Configuración de Docker Compose

El servidor espera un contenedor de ModSecurity gestionado por Docker Compose. Ejemplo de definición de servicio:

modsecurity:
  image: owasp/modsecurity-crs:nginx-alpine
  environment:
    - BACKEND=http://your-app:8080
    - MODSEC_RULE_ENGINE=DetectionOnly
    - MODSEC_AUDIT_LOG=/dev/stderr
    - MODSEC_AUDIT_LOG_FORMAT=JSON
    - MODSEC_AUDIT_LOG_TYPE=Serial
    - MODSEC_AUDIT_ENGINE=RelevantOnly
    - MODSEC_REQ_BODY_ACCESS=On
    - MODSEC_REQ_BODY_LIMIT=52428800
    - MODSEC_RESP_BODY_ACCESS=Off
    - PARANOIA=1
    - ANOMALY_INBOUND=5
  volumes:
    - ./modsecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:ro

Ajustes clave:

  • MODSEC_AUDIT_LOG=/dev/stderr — envía el registro de auditoría a los registros de Docker (requerido para que el servidor MCP lea los eventos)
  • MODSEC_AUDIT_LOG_FORMAT=JSON — formato JSON para análisis estructurado
  • Montaje del archivo de exclusiones — permite la recarga en caliente de las exclusiones de reglas mediante nginx -s reload

Exclusiones del CRS para tráfico de LLM

Los endpoints de API de LLM reciben prompts que contienen código, SQL, HTML y comandos de shell, todo contenido legítimo que activa las reglas del WAF. Crea un archivo de exclusiones para deshabilitar las reglas de inspección de contenido en las rutas de API:

# modsecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
SecRule REQUEST_URI "@rx ^(/v1/)?(chat/completions|completions|embeddings|responses|messages)|^/anthropic/" \
    "id:1000,phase:1,nolog,pass,\
    ctl:ruleRemoveById=921000-944999"

Esto deshabilita las reglas 921000–944999 (todas las categorías de inspección de contenido: SQLi, XSS, RCE, LFI, RFI, etc.) en los endpoints de API de LLM, manteniendo activos el cumplimiento del protocolo, la detección de escáneres, la protección contra DoS y las comprobaciones de reputación de IP.

Ejemplo de uso

Flujo de trabajo típico en Claude Code:

You: "Check the WAF — anything suspicious?"

Claude: [calls waf_overview]
  → 332 events, 4 unique IPs, 12 rules triggered

Claude: [calls waf_top_ips]
  → 135.237.83.23 (Washington, US, Microsoft) — 320 events

Claude: [calls waf_events_by_ip, ip: "135.237.83.23", count: 5]
  → All POST /chat/completions, HTTP 200, rules: 942360, 932100...

Claude: [calls waf_event_detail, index: 42]
  → User-Agent: OpenAI/JS 6.26.0, body contains tool descriptions
  → Rule 942360 matched "update" in cron action descriptions

Claude: "This is your OpenClaw bot — all false positives.
         Want me to whitelist this IP?"

You: "Yes"

Claude: [calls waf_allow_ip, ip: "135.237.83.23"]
  → Done. IP whitelisted.

Investigando eventos antiguos:

You: "Check IP 185.206.249.230 — it was flagged yesterday"

Claude: [calls waf_events_by_ip, ip: "185.206.249.230", since: "7d"]
  → 2 events from Apr 7, GET /v1/skills, HTTP 401, no rules triggered
  → Apple Private Relay IP (Singapore), just unauthorized API probes

Desarrollo

npm run build        # Compile TypeScript
npm test             # Run tests (43 tests)
npm run test:watch   # Watch mode
WAF_DEBUG=1 npm start  # Run with debug logging

Arquitectura

src/
├── index.ts           # MCP server setup, tool registration
├── waf-manager.ts     # Core service: Docker exec, log parsing, config management
├── types.ts           # TypeScript interfaces
├── config.ts          # Environment-based configuration
├── logger.ts          # stderr-only logger (stdout reserved for MCP protocol)
└── tools/
    ├── overview.ts        # L0: dashboard
    ├── top-ips.ts         # L1: IP aggregation
    ├── top-rules.ts       # L1: rule aggregation
    ├── fp-candidates.ts   # L1: false positive detection
    ├── events-by-ip.ts    # L2: drill-down by IP
    ├── events-by-rule.ts  # L2: drill-down by rule
    ├── event-detail.ts    # L3: full event inspection
    ├── status.ts          # Container status
    ├── set-engine.ts      # Engine mode control
    ├── set-paranoia.ts    # Paranoia level control
    ├── disable-rule.ts    # Rule management
    ├── enable-rule.ts     # Rule management
    ├── allow-ip.ts        # IP whitelist
    ├── deny-ip.ts         # IP whitelist
    ├── test.ts            # WAF test suite
    └── utils.ts           # Shared utilities

Los eventos se analizan desde los registros de Docker y se almacenan en caché durante 30 segundos. Las llamadas rápidas de exploración descendente (resumen → IPs principales → eventos por IP → detalle del evento) acceden a la caché en lugar de volver a analizar. La caché se invalida cuando cambia el parámetro since.

Licencia

MIT