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:
- Resumen — ver eventos totales, IPs únicas y reglas activas de un vistazo
- Exploración descendente — filtrar eventos por IP o regla, inspeccionar los datos coincidentes
- 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)
| Herramienta | Descripción |
|---|---|
waf_overview | Panel: eventos totales, IPs/reglas únicas, eventos de la última hora |
waf_top_ips | IPs principales por número de eventos con enriquecimiento geográfico (ipinfo.io) |
waf_top_rules | Reglas más activadas con severidad y descripción |
waf_fp_candidates | Reglas que se activaron en respuestas HTTP 2xx (candidatas a falsos positivos) |
waf_events_by_ip | Eventos filtrados por IP de origen |
waf_events_by_rule | Eventos filtrados por ID de regla |
waf_event_detail | Evento completo: cabeceras, cuerpo de la solicitud, todas las coincidencias de reglas con los datos coincidentes |
Acciones
| Herramienta | Descripción |
|---|---|
waf_status | Estado del contenedor, modo del motor, reglas cargadas, nivel de paranoia |
waf_set_engine | Cambiar entre On, Off, DetectionOnly |
waf_set_paranoia | Establecer el nivel de paranoia del CRS (1–4) |
waf_disable_rule | Deshabilitar una regla por ID (añade SecRuleRemoveById a las exclusiones) |
waf_enable_rule | Volver a habilitar una regla previamente deshabilitada |
waf_allow_ip | Incluir una IP en la lista blanca (omitir el WAF por completo) |
waf_deny_ip | Eliminar una IP de la lista blanca |
waf_test | Ejecutar 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:
| Campo | Predeterminado | Detallado |
|---|---|---|
matchedData (por regla) | 150–200 caracteres | 4000 caracteres |
requestBody | 500 caracteres | 8000 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
| Variable | Requerida | Predeterminado | Descripción |
|---|---|---|---|
WAF_COMPOSE_DIR | Sí | — | Ruta al directorio que contiene docker-compose.yml |
WAF_DOMAIN | No | https://localhost | Dominio para solicitudes de prueba del WAF |
WAF_LOGS_SINCE | No | 24h | Ventana de tiempo predeterminada para consultas de registros |
WAF_CONTAINER_PATTERN | No | modsecurity | Patrón grep para encontrar el contenedor de ModSecurity |
WAF_EXCLUSIONS_FILE | No | modsecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf | Ruta al archivo de exclusiones del CRS (relativa al directorio de compose) |
WAF_COMPOSE_FILE | No | docker-compose.yml | Nombre del archivo de Docker Compose |
IPINFO_TOKEN | No | — | Token de ipinfo.io para geolocalización de IPs |
WAF_DEBUG | No | — | 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