Volver a actualizaciones
Nuevo releaseSep 3, 2026

laravel-threat-detection v1.7.2

Middleware pasivo de Laravel que detecta y registra inyección SQL, XSS, RCE, escáneres de bots y más de 175 patrones de ataque. Incluye un panel integrado, alertas de Slack, API REST y enriquecimiento geográfico. IDS, no WAF.

Compartir

Latest Version Tests PHPStan Level 5 Code Style Pint Total Downloads PHP Version License

Detección de Amenazas para Laravel

Monitoreo de seguridad y registro de ataques para Laravel. Detecta y registra inyección SQL, XSS, RCE, traversal de directorios, escáneres de bots y sondas de reconocimiento estilo /wp-admin — cada solicitud hostil se registra en tu base de datos con contexto completo de la aplicación. Es un IDS, no un WAF: nunca bloquea, filtra ni modifica una solicitud.

Instala el paquete, envía tres ataques — inyección SQL, traversal de directorios, XSS — cada uno devuelve HTTP 200 porque nada se bloquea, y los tres ya se cuentan en threat-detection:stats

¿Estás aquí porque viste algo como esto?```

GET /wp-admin/setup-config.php 404 — on a site that isn't WordPress GET /.env 404 — someone wants your database password GET /?id=1' UNION SELECT password FROM 200 — SQL injection against a real route GET /phpmyadmin/index.php 404 — scanning for an admin panel

Esas solicitudes ya están llegando a tu aplicación Laravel. Tu registro de acceso muestra la URL
y el código de estado, y nada más — ni el payload decodificado, ni a cuál de tus
rutas se dirigió, ni si la misma IP ha intentado otras cuarenta cosas en esta hora.

Este paquete responde a esas preguntas. Introdúcelo en cualquier aplicación Laravel 10–13 y comenzará
a escanear cada solicitud HTTP contra más de 150 patrones de ataque, puntuando cada coincidencia por
confianza y escribiéndola en tu base de datos — con un panel integrado, alertas de Slack,
enriquecimiento geográfico y exportaciones para fail2ban/listas de bloqueo. Ninguna solicitud se bloquea jamás. Piensa en
una cámara de seguridad, no en un candado: te muestra exactamente quién está sondeando tus rutas, con qué
frecuencia y con qué técnicas.

> Extraído de una aplicación en producción y probado en tráfico real. 335 pruebas, sin dependencias
> de ejecución más allá del propio Laravel, y sin necesidad de conexión a internet para la detección.
>
> ¿Actualizando? Consulta [UPGRADING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/UPGRADING.md). ¿Contribuyendo? Consulta [CONTRIBUTING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/CONTRIBUTING.md).

## Empieza en menos de un minuto```bash
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Luego añade el middleware a tu grupo web (una línea en bootstrap/app.php en Laravel 11+, o app/Http/Kernel.php en Laravel 10) — el fragmento completo está en Inicio rápido más abajo. Eso es todo; la detección ya está activa.```bash php artisan threat-detection:doctor # confirms it is actually recording

---

## Dónde encaja: IDS vs WAF vs edge

Este paquete es un **IDS pasivo a nivel de aplicación** — observa y registra, no
bloquea. Está pensado para situarse *junto a* un WAF o un servicio edge, no para
sustituirlo. Cada capa ve algo que las demás no pueden ver:

| | **Este paquete** (IDS de app) | **WAF** (mod_security, Cloudflare WAF) | **Edge / CDN** (Cloudflare) |
|---|:---:|:---:|:---:|
| Bloquea peticiones maliciosas | ❌ solo registra | ✅ | ✅ |
| Contexto completo de la app (ruta exacta, payload decodificado, usuario autenticado) | ✅ | ⚠️ parcial | ❌ |
| Panel integrado + registro de amenazas en tu BD | ✅ | ⚠️ varía | ⚠️ solo edge |
| Detecciones específicas de la app (p. ej. PII de Aadhaar / PAN / IFSC) | ✅ patrones personalizados | ❌ | ❌ |
| Funciona sin conexión / sin servicio externo | ✅ | ⚠️ depende | ❌ |
| Detiene el tráfico antes de que llegue a tu app | ❌ | ✅ edge | ✅ |
| Configuración | un `composer require` | media–alta | baja–media |
| Coste | gratis, MIT | varía | nivel gratuito + de pago |

**La versión corta:** un edge/WAF es tu cerradura en la puerta; esto es la cámara de
seguridad *del interior*, con el contexto de la app para decirte exactamente qué se está
intentando en cada ruta, por quién y con qué frecuencia. Úsalo para alimentar decisiones
reales — baneos de fail2ban, límites de tasa, bloqueo geográfico — con datos que tu capa
edge nunca ve.

### Lo que deliberadamente NO es

- **No es un WAF.** Nunca bloquea, filtra ni modifica una petición. Usa Cloudflare,
  mod_security o un WAF real para la aplicación de políticas. (¿No tienes capa edge a la
  que delegar? Los [helpers del lado del operador](#acting-on-the-data-operator-side-blocking)
  exponen las decisiones del paquete para que escribas tu propio middleware de bloqueo de
  cinco líneas — el código de aplicación de políticas sigue siendo tuyo, no del paquete.)
- **No sustituye a la codificación segura.** Las consultas parametrizadas, la validación de
  entrada y el escape de salida son tus defensas reales. Este paquete asume que tu código ya
  es seguro y te da *visibilidad*, no protección.
- **No es un servicio edge.** Si puedes poner Cloudflare delante, hazlo — y luego añade esto
  para el detalle a nivel de aplicación que los servicios edge no pueden ver.

### Entonces, ¿qué haces realmente con él?

La pregunta más común sobre un detector que nunca bloquea. Cuatro respuestas, en
orden creciente de esfuerzo:

| Quieres | Usa | Esfuerzo |
|---|---|---|
| Ver qué te está atacando | El [panel](#dashboard) o `threat-detection:stats` | ninguno, ya está en ejecución |
| Banear a los reincidentes en el firewall | [`threat-detection:export-fail2ban`](#artisan-commands) — canalízalo a un cron | una línea |
| Denegar en el servidor web | [`threat-detection:export-blocklist`](#artisan-commands) → directivas de nginx/apache | una línea |
| Rechazar peticiones en la app | [Helpers del lado del operador](#acting-on-the-data-operator-side-blocking) — `isBlocklisted()`, `isDdosThresholdExceeded()` | ~10 líneas de tu propio middleware |
| Reaccionar en tiempo real | El [evento `ThreatDetected`](#threatdetected-event) — Telegram, SIEM, PagerDuty | un listener |

El paquete aporta la inteligencia; tú aportas el rechazo. Esa división es
deliberada — el código de aplicación de políticas que vive en tu app es código que puedes
leer, probar y desactivar, y significa que un fallo de detección nunca puede tumbar tu sitio.

### Cómo se compara con otros paquetes de seguridad de Laravel

Estos resuelven problemas distintos y se complementan bien — la tabla trata de elegir la
herramienta adecuada, no de ganar.

| Paquete | Qué hace | ¿Bloquea? | Úsalo cuando |
|---|---|:---:|---|
| **este paquete** | Escanea cada petición contra más de 150 patrones, registra con contexto completo de la app | ❌ | Quieres *ver* qué se está intentando contra tu app |
| `spatie/laravel-honeypot` | Campo de formulario oculto que atrapa bots de spam | ✅ solo formulario | Tienes formularios públicos que reciben spam |
| `graham-campbell/security` | Elimina marcado tipo XSS de la entrada | ✅ muta | Quieres saneamiento ingenuo de entrada |
| `spatie/laravel-csp` | Envía cabeceras Content-Security-Policy | ✅ navegador | Quieres restringir lo que carga el navegador |
| `laravel/fortify` + límites de tasa | Limitación de autenticación y bloqueo | ✅ | Necesitas protección contra fuerza bruta en el inicio de sesión |
| Cloudflare / mod_security | WAF edge, bloquea antes de tu app | ✅ | Quieres que el tráfico se detenga antes de llegar |

El resumen honesto: un honeypot atrapa el spam de formularios, un WAF bloquea el tráfico
conocido como malo en el edge y CSP restringe el navegador. **Ninguno de ellos te dice qué
intentó un atacante contra tus rutas específicas, con el payload decodificado y el usuario
autenticado adjunto.** Ese vacío es lo que esto cubre — y es por eso que el paquete
deliberadamente no bloquea: puedes ejecutarlo junto a todo lo anterior
sin que ninguno interfiera con los demás.

---

## Requisitos

- PHP 8.2+ (Laravel 13 requiere PHP 8.3+)
- Laravel 10.x, 11.x, 12.x o 13.x
- Cualquier base de datos compatible con Laravel (MySQL, PostgreSQL, SQLite, SQL Server)
- Cualquier driver de caché — **no se requiere Redis ni worker de colas**. Redis/Memcached
  solo se *recomienda* para habilitar la comprobación opcional de DDoS (que se desactiva
  automáticamente en drivers no atómicos). Las escrituras en cola son opcionales y están
  desactivadas por defecto.

---

## Cómo funciona

1. Un middleware escanea cada petición HTTP entrante
2. La petición se comprueba contra 158 patrones regex que cubren inyección SQL, XSS, RCE, traversal de archivos, SSRF, LDAP, XPath, SSTI y más
3. Si un patrón de amenaza coincide, se escribe un registro en tu tabla de base de datos `threat_logs` con la IP, la URL, el tipo de amenaza, el nivel de severidad y una puntuación de confianza
4. Opcionalmente, se envía una alerta de Slack para amenazas de alta severidad
5. La petición continúa con normalidad — **no se bloquea nada**

No se necesita conexión a internet para la detección.

---

## Inicio rápido

### 1. Instala el paquete```bash
composer require jayanta/laravel-threat-detection

2. Publicar las migraciones y ejecutarlas

Este paso es obligatorio. Sin él, el paquete detectará amenazas pero no podrá almacenarlas en la base de datos. Si omites este paso, tu tabla threat_logs no existirá y todas las detecciones se perderán silenciosamente (solo verás errores en storage/logs/laravel.log).```bash php artisan vendor:publish --tag=threat-detection-migrations php artisan migrate

Esto crea dos tablas: `threat_logs` (almacena amenazas detectadas) y `threat_exclusion_rules` (almacena reglas de falsos positivos).

**Verifica que las tablas se hayan creado:**```bash
php artisan migrate:status

Look for create_threat_logs_table, add_confidence_to_threat_logs_table, y create_threat_exclusion_rules_table - todos deberían mostrar Ran.

3. Registrar el middleware

El middleware es lo que escanea las solicitudes. Debes agregarlo a tu grupo de middleware web.

Si usas Laravel 11 o 12 - abre bootstrap/app.php:```php ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ \JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class, ]); })

> **Cómo comprobar tu versión de Laravel:** Ejecuta `php artisan --version` en tu terminal.

**Si usas Laravel 10** - abre `app/Http/Kernel.php`:```php
protected $middlewareGroups = [
    'web' => [
        // ... existing middleware
        \JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class,
    ],
];

4. (Opcional) Publicar el archivo de configuración```bash

php artisan vendor:publish --tag=threat-detection-config

El paquete funciona con valores predeterminados sensatos. Publicar la configuración te permite personalizar los patrones de detección, los modos de sensibilidad, las notificaciones de Slack y más. Si omites este paso, todo sigue funcionando.

**Eso es todo.** Tu aplicación ahora está detectando amenazas.

---

## Verifica que funciona

Después de la instalación, activa una amenaza de prueba y confirma que se registró.

### Paso 1: Inicia tu aplicación```bash
php artisan serve

Paso 2: Abre una URL de prueba en tu navegador

Añade un parámetro de consulta malicioso a cualquier ruta existente en tu aplicación (tu página de inicio, una página de producto, etc.). Por ejemplo:

Inyección SQL:``` http://localhost:8000/?q=' UNION SELECT * FROM users--

**XSS (Cross-Site Scripting):**```
http://localhost:8000/?q=<script>alert(1)</script>

Directory Traversal:``` http://localhost:8000/?file=../../etc/passwd

**RCE (Ejecución Remota de Código):**```
http://localhost:8000/?cmd=system('ls -la')

Shellshock (CVE-2014-6271):``` http://localhost:8000/?cmd=() { :;}; /bin/bash

**Inyección de comandos en Windows:**```
http://localhost:8000/?cmd=powershell -c whoami

DROP TABLE (DDL de SQL):``` http://localhost:8000/?q=DROP TABLE users

> Usa una ruta que realmente exista en tu aplicación (como `/`). Si la URL devuelve un 404, es posible que el middleware no se haya ejecutado.

### Paso 3: Verifica que las amenazas se hayan registrado

**Opción A - Comando de Artisan (la más rápida):**```bash
php artisan threat-detection:stats

Opción B - Tinker:```bash php artisan tinker

```php
DB::table('threat_logs')->latest()->take(5)->get(['ip_address', 'type', 'threat_level', 'confidence_score']);

Opción C - Archivo de registro de Laravel: Cada amenaza detectada se escribe como una advertencia en storage/logs/laravel.log:``` [high] Threat Detected: [middleware] SQL Injection UNION from 127.0.0.1 (http://localhost:8000/?q=...) [confidence: 50%]

### Cosas a tener en cuenta al probar

| Comportamiento | Explicación |
|----------|-------------|
| La misma amenaza solo se registra una vez cada 5 minutos | Deduplicación: la misma IP + el mismo tipo de amenaza se almacena en caché durante 5 minutos. Usa **tipos de ataque diferentes** para cada prueba, o espera entre pruebas. |
| Las solicitudes `curl` activan detección adicional | Usar `curl` también registra una detección de user-agent "cURL Command" (severidad baja). Esto es esperado: el paquete detecta herramientas automatizadas. |
| El paquete nunca bloquea solicitudes | Tu aplicación sigue funcionando con normalidad. La detección es pasiva. |
| No se necesita configuración de Slack | Las notificaciones están desactivadas por defecto. |
| No se necesita conexión a internet | La detección principal es 100 % local. Solo el comando opcional `threat-detection:enrich` llama a una API externa para datos geográficos. |

### Solución de problemas

**Empieza aquí: un solo comando responde la mayoría de esto:**```bash
php artisan threat-detection:doctor

Comprueba las cosas que hacen que la detección falle silenciosamente — donde el panel permanece vacío, lo que parece idéntico a "sin ataques" — e imprime la corrección exacta para cada una. Sale con código distinto de cero ante un fallo real, por lo que es seguro ejecutarlo en CI o en un paso de despliegue.``` Threat Detection — health check

PASS Detection is enabled for this environment FAIL 'threat_logs' is missing confidence_label — EVERY threat is being discarded Run: php artisan vendor:publish --tag=threat-detection-migrations && php artisan migrate WARN 1 custom pattern(s) shadow a built-in: Localhost SSRF Your copy runs instead of the maintained one, so later fixes to it never reach you.

Qué cubre: detección habilitada para este entorno; cada columna que el escritor
necesita (una que falte descarta **todas** las amenazas); columnas del panel/API; la
tabla de reglas de exclusión; si el middleware está realmente conectado a una ruta o
grupo; configuración publicada que es anterior a esta versión; patrones personalizados que
ocultan los integrados; un controlador de caché que no puede realizar el conteo de DDoS; y un panel o
API dejados abiertos sin autenticación.

**"Probé pero `threat-detection:stats` muestra cero amenazas" / "Las amenazas no se almacenan en la base de datos"**

Si el doctor pasó, la instalación está bien y el problema es la solicitud de prueba
en sí. Tres cosas que no puede verificar por ti:

| Comprobación | Cómo verificar |
|-------|---------------|
| La IP no está en la lista blanca | Si agregaste `THREAT_DETECTION_WHITELISTED_IPS` a `.env`, elimínalo durante las pruebas |
| Se usó una ruta existente | La URL de prueba debe coincidir con una ruta real (p. ej., `/`). Un 404 significa que el middleware nunca se ejecutó |
| Caché de deduplicación | Misma IP + mismo tipo de ataque se almacena en caché durante 5 minutos: prueba con un tipo de ataque diferente |

> Ejecutar `php artisan migrate` por sí solo nunca es suficiente: los archivos de migración viven
> dentro del paquete y deben publicarse en `database/migrations/` de tu aplicación
> primero. El doctor imprime el comando exacto cuando este es el problema.

**"La API devuelve 401 Unauthorized"**

Consulta [Autenticación de API](#api-authentication) a continuación.

**"El panel muestra 404"**

El panel está deshabilitado por defecto. Agrega `THREAT_DETECTION_DASHBOARD=true` a `.env` y limpia la caché de rutas:```bash
php artisan route:clear

Características

  • Más de 150 patrones de detección - Inyección SQL (UNION, DDL, DML, operaciones de archivos), XSS (script, SVG, expresión CSS), RCE, directory traversal, SSRF, XXE, Log4Shell, inyección NoSQL, inyección de comandos (Linux + Windows), inyección LDAP, inyección XPath, SSTI, inyección CRLF, deserialización de Java y más
  • 83 firmas de bots/escáneres - SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker y más de 70 firmas de escáneres y bots
  • Detección de scrapers de IA - GPTBot, ClaudeBot, ByteSpider, Common Crawl y otros bots de entrenamiento de IA
  • Detección de navegadores headless - HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright
  • Seguimiento de sondas 404 - Detecta sondas de reconocimiento que acceden a rutas vulnerables conocidas (/wp-admin, /.env, /phpmyadmin, /actuator, etc.) con más de 50 rutas de sonda predeterminadas
  • Monitoreo de DDoS - Detección de umbral basada en tasas con ventanas configurables
  • Puntuación de confianza - Cada amenaza recibe una puntuación de confianza de 0 a 100 basada en el número de patrones, el contexto y las señales
  • Resistencia a la evasión - El pipeline de normalización neutraliza la inserción de comentarios SQL, la doble codificación URL, la codificación de entidades HTML, los escapes Unicode y los escapes hexadecimales antes de la coincidencia de patrones
  • Detección de CVEs - Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
  • Detección consciente del contexto - Los patrones encontrados en cadenas de consulta puntúan más alto que los del cuerpo de la solicitud
  • Escaneo del cuerpo de la solicitud - Se inspeccionan tanto los cuerpos codificados como formulario como los JSON (application/json)
  • Campos seguros - Excluye campos de formulario específicos del escaneo (para editores CMS, entradas de código, campos de búsqueda)
  • Informe de falsos positivos - Marca amenazas como falsos positivos desde el panel; crea automáticamente reglas de exclusión
  • Tres modos de detección - strict, balanced (predeterminado) y relaxed - sensibilidad ajustable
  • Supresión por ruta de contenido - Lista blanca de rutas CMS/blog para suprimir alertas bajas/medias de contenido enriquecido
  • Detección de PII - Patrones de exposición de datos sensibles (configurables por región)
  • Enriquecimiento geográfico - Identificación de país, ciudad, ISP y proveedor de nube mediante API gratuita
  • Alertas de Slack - Notificaciones en tiempo real para amenazas de alta severidad (funciona en Laravel 10 y 11+)
  • Panel integrado - Panel Blade en modo oscuro (Alpine.js + Tailwind CDN, sin paso de compilación)
  • Guardia de autenticación del panel - Autenticación configurable para el panel y la API (ninguna, auth, rol o basada en IP)
  • 15 endpoints de API - API REST completa para crear paneles personalizados en Vue/React/móvil
  • Exportación Fail2ban - Exporta IPs detectadas en formato compatible con fail2ban o como lista de bloqueo simple
  • Exportación de lista de bloqueo - Exporta IPs en formato deny de nginx, deny de Apache, CSV o texto plano
  • Exportación CSV - Exportación de registros de amenazas con un clic (hasta 10,000 filas)
  • Análisis de correlación - Detecta ataques coordinados y campañas de ataque entre IPs
  • Optimizado para rendimiento - Carga diferida de patrones por categoría (solo ejecuta regex para categorías de ataque relevantes), salida anticipada para solicitudes limpias, cortocircuito de UA de navegador (omite más de 70 comprobaciones para navegadores normales), búsqueda hash de rutas de sonda, inserciones DB por lotes, máximo de detecciones configurable por solicitud
  • Independiente de la base de datos - MySQL, PostgreSQL, SQLite, SQL Server
  • Cero configuración - Funciona de inmediato con valores predeterminados sensatos
  • Seguro por diseño - El middleware captura sus propios errores. Si la detección falla, tu aplicación sigue funcionando. Las solicitudes nunca se bloquean.

Configuración

El paquete funciona sin ningún cambio en .env. Todos los valores siguientes son opcionales: agrégalos solo si deseas sobrescribir los valores predeterminados.```env

Enable/disable detection globally (default: true)

THREAT_DETECTION_ENABLED=true

Detection sensitivity (default: balanced)

Options: strict, balanced, relaxed

THREAT_DETECTION_MODE=balanced

Custom table name (default: threat_logs)

THREAT_DETECTION_TABLE=threat_logs

Your ISO 3166-1 alpha-2 country code (default: IN)

Drives the is_foreign flag on every enriched row — set this or every

non-Indian address is reported as foreign.

THREAT_DETECTION_HOME_COUNTRY=IN

Geo-enrichment provider used by threat-detection:enrich (default shown).

Cleartext HTTP because ip-api.com's free tier rejects HTTPS; point this at

an HTTPS endpoint if you hold a key. Enrichment is opt-in either way.

THREAT_DETECTION_GEO_ENDPOINT=http://ip-api.com/json

Dashboard URL path (default: threat-detection)

THREAT_DETECTION_DASHBOARD_PATH=threat-detection

API route prefix (default: api/threat-detection)

THREAT_DETECTION_API_PREFIX=api/threat-detection

Role required when the API guard is 'role' (default: admin)

THREAT_DETECTION_API_ROLE=admin

Allowed IPs when the API guard is 'ip'. Comma-separated, CIDR supported.

THREAT_DETECTION_API_IPS=127.0.0.1,10.0.0.0/8

Username shown on Slack alerts (default: ThreatBot)

THREAT_DETECTION_SLACK_USERNAME=ThreatBot

Whitelist IPs to skip detection entirely (default: empty)

Supports CIDR notation. Comma-separated.

THREAT_DETECTION_WHITELISTED_IPS=10.0.0.0/8,192.168.1.0/24

Static operator denylist read by ThreatDetection::isBlocklisted() (default: empty)

The package itself never blocks — see "Acting on the Data" for the

enforcement recipe. Supports CIDR. Whitelist wins on overlap.

THREAT_DETECTION_BLOCKLISTED_IPS=203.0.113.0/24,198.51.100.7

DDoS detection thresholds (defaults shown)

THREAT_DETECTION_DDOS_THRESHOLD=300

THREAT_DETECTION_DDOS_WINDOW=60

Minimum confidence score to log a threat (default: 0)

Threats below this score are silently ignored.

THREAT_DETECTION_MIN_CONFIDENCE=0

Slack notifications (disabled by default)

THREAT_DETECTION_NOTIFICATIONS=true

THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL

THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Dashboard (disabled by default)

THREAT_DETECTION_DASHBOARD=true

API endpoints (enabled by default)

THREAT_DETECTION_API=true

API rate limiting (default: 60 requests per minute)

THREAT_DETECTION_API_THROTTLE=60,1

Queue support - offload DB writes to a queue (disabled by default).

OPTIONAL: only enable if your app already runs a queue worker. When false

(default), threats are written synchronously with a plain DB insert - no

Redis, no worker, nothing extra to run.

THREAT_DETECTION_QUEUE=false

THREAT_DETECTION_QUEUE_CONNECTION=redis

THREAT_DETECTION_QUEUE_NAME=default

Auto-purge old logs (disabled by default)

Requires Laravel scheduler to be running.

THREAT_DETECTION_RETENTION=false

THREAT_DETECTION_RETENTION_DAYS=90

404 probe tracking (enabled by default)

Detects bots hitting /wp-admin, /.env, /phpmyadmin, etc.

THREAT_DETECTION_PROBE_TRACKING=true

Max detections per request (default: 0 = unlimited)

Stop scanning after N pattern matches per request.

THREAT_DETECTION_MAX_DETECTIONS=0

Dashboard auth guard (default: none)

Options: none, auth, role, ip

THREAT_DETECTION_DASHBOARD_GUARD=none

THREAT_DETECTION_DASHBOARD_ROLE=admin

THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

API auth guard (default: none - uses existing middleware config)

THREAT_DETECTION_API_GUARD=none

### Modos de Detección

| Modo | Umbral de Confianza | Comportamiento |
|------|---------------------|----------|
| `strict` | 0 (registra todo) | Todos los patrones activos, umbrales más bajos. Detecta todo, pero puede marcar tráfico legítimo. |
| `balanced` | 10 | Predeterminado. Puntuación de confianza activa, umbrales estándar. Bueno para la mayoría de las aplicaciones. |
| `relaxed` | 40 | Solo se activan los patrones de alta severidad. Ideal para sitios con mucho contenido y falsos positivos frecuentes. |

### Entornos Habilitados

Por defecto, la detección se ejecuta en `production`, `staging` y `local`. Para cambiarlo, publique la configuración y edite:```php
'enabled_environments' => ['production', 'staging', 'local'],

Para deshabilitar la detección en tu suite de pruebas, establece APP_ENV=testing (no está en la lista anterior) o añade a tu phpunit.xml:```xml

### Referencia de configuración

Publica el archivo de configuración para ver todas las opciones disponibles:```bash
php artisan vendor:publish --tag=threat-detection-config

Secciones clave de configuración: skip_paths (rutas a omitir), only_paths (modo lista blanca), auth_paths (detección inteligente de rutas de inicio de sesión), content_paths (suprimir alertas no críticas), safe_fields (excluir campos específicos del escaneo), safe_paths (exclusión de campos según ruta para JSON anidado), probe_tracking (detección de sondas 404), context_weights (multiplicadores de puntuación), threat_levels (mapeo de palabras clave de severidad), api_route_filtering (suprimir alertas bajas/medias en rutas API), queue (procesamiento asíncrono), retention (purga automática), max_detections_per_request (límite de rendimiento), dashboard.guard / api.guard (modo de autenticación).

Lista blanca de rutas (only_paths)

Si tu aplicación tiene muchas rutas pero solo te interesan unas pocas, usa only_paths para escanear solo esas rutas. Todas las demás rutas se omiten automáticamente: sin sobrecarga de middleware en absoluto.```php // config/threat-detection.php 'only_paths' => [ 'admin/', 'api/', 'login', 'register', ],

Déjalo vacío (por defecto) para escanear todas las rutas (sujeto a `skip_paths`). Cuando ambos están configurados, `only_paths` se comprueba primero y luego `skip_paths` se aplica dentro del conjunto coincidente.

### Soporte de colas

Por defecto, el registro de amenazas ocurre de forma síncrona en el ciclo de solicitud. Para aplicaciones de alto tráfico, puedes descargar las escrituras en la base de datos y las notificaciones de Slack a una cola:```env
THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=threat-logs

Esto despacha un trabajo StoreThreatLog (3 reintentos, retroceso 10s/30s). La detección sigue ocurriendo en tiempo real: solo la escritura se difiere.

Purga automática (Política de retención)

Elimina automáticamente los registros de amenazas antiguos según un horario diario:```env THREAT_DETECTION_RETENTION=true THREAT_DETECTION_RETENTION_DAYS=90

Requiere que el programador de Laravel esté en ejecución (`php artisan schedule:run`). Se ejecuta diariamente a las 02:00 mediante `threat-detection:purge`.

### Evento ThreatDetected

Cada amenaza confirmada despacha un evento `ThreatDetected` al que puedes suscribirte:```php
// app/Providers/EventServiceProvider.php
use JayAnta\ThreatDetection\Events\ThreatDetected;

protected $listen = [
    ThreatDetected::class => [
        YourCustomListener::class,
    ],
];

El evento lleva $threatLog (array completo de la fila de la BD), $ipAddress y $threatLevel. Úsalo para activar acciones personalizadas: enviar alertas de Telegram, actualizar una lista de bloqueo, alimentar un SIEM, etc.

Evento DdosThresholdExceeded

Cuando un cliente supera el umbral de DDoS configurado (ddos.threshold solicitudes dentro de ddos.window segundos), se despacha un evento DdosThresholdExceeded junto con la entrada del registro de amenazas:```php use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;

protected $listen = [ DdosThresholdExceeded::class => [ YourFloodListener::class, ], ];

El evento lleva `$ipAddress`, `$requestCount`, `$threshold` y `$windowSeconds`. Se
limita a una vez por IP por ventana de deduplicación (el mismo límite que la fila de registro), por lo que una inundación no puede
ahogar tus listeners. Úsalo para alertas o para alimentar un almacén de baneo externo; para *rechazar*
clientes que superen el umbral, usa `ThreatDetection::isDdosThresholdExceeded($ip)` desde tu propio
middleware en su lugar — consulta [Actuando sobre los datos](#acting-on-the-data-operator-side-blocking).

---

## Notificaciones de Slack

Las alertas de Slack están deshabilitadas por defecto. Para habilitarlas:```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Solo las amenazas de alta severidad activan notificaciones por defecto (configurable mediante notify_levels en la configuración).

Laravel 10: Utiliza la clase de notificación integrada SlackMessage. No se necesita ningún paquete adicional.

Laravel 11+: El canal de Slack integrado fue eliminado. El paquete detecta esto automáticamente y envía webhooks HTTP POST sin procesar a tu URL de Slack. No se necesita ningún paquete adicional. Si prefieres el canal de notificación completo, instala:```bash composer require laravel/slack-notification-channel

---

## Panel de control

<p align="center">
  <img src="https://assets.kitploit.com/production/public/readmes/12500/fc7950bd0cc6323bcc2d62b03e31c99edc7450b0ef76f9cbfa5133b527b25269.png" alt="Panel de detección de amenazas: estadísticas, cronología de 7 días, registro de amenazas en vivo, principales IP infractoras y amenazas por país" width="100%">
</p>

El paquete incluye un panel de control integrado con modo oscuro (Alpine.js + Tailwind CDN, sin necesidad de paso de compilación).```
+-------------------------------------------------------------------------+
|  Threat Detection Dashboard                                              |
+-------------------------------------------------------------------------+
|  Total: 847  |  High: 23  |  Med: 156  |  Low: 668  |  IPs: 94         |
+-------------------------------------------------------------------------+
|  [Timeline Chart - 7 Day Stacked Bar]                                   |
+-------------------------------------------------------------------------+
|  Search: [___________]  Level: [All]                                    |
|  Time         IP             Type            Level  Confidence  Actions  |
|  Mar 2 14:02  185.220.101.4  SQL Injection   HIGH   80%         [FP]    |
|  Mar 2 13:58  45.33.32.156   XSS Script Tag  HIGH   65%         [FP]    |
|  Mar 2 13:45  192.168.1.10   Scanner: Nikto  MED    35%         [FP]    |
+-------------------------------------------------------------------------+
|  Top IPs              |  Threats by Country                              |
|  185.220.101.4  [23]  |  US  234                                        |
|  45.33.32.156   [18]  |  CN  156                                        |
|  103.152.220.1  [12]  |  RU  98                                         |
+-------------------------------------------------------------------------+

Habilitar el panel de control

Añade a .env:```env THREAT_DETECTION_DASHBOARD=true

Visita: `http://your-app.test/threat-detection`

### Acceso durante el desarrollo local

El panel utiliza el middleware `['web', 'auth']` por defecto, por lo que los usuarios deben haber iniciado sesión. Si tu aplicación aún no tiene autenticación, restringe el acceso solo a tu propia máquina:```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

Todas las opciones de guard, y el guard separado en los endpoints que desactivan las detecciones, están cubiertos en Autenticación del Dashboard y de la API.

Si el dashboard muestra datos vacíos, la página cargó pero sus llamadas a la API no lo hicieron. Consulta Autenticación de la API.


Endpoints de la API

El paquete proporciona 15 endpoints REST para construir dashboards o integraciones personalizados.

Autenticación de la API

Las rutas de la API usan el middleware auth:sanctum por defecto. El paquete maneja esto de forma elegante:

  • Sanctum instalado: La API requiere autenticación mediante tokens de Sanctum o autenticación de sesión SPA.
  • Sanctum NO instalado: El paquete detecta automáticamente que Sanctum falta y recurre solo a ['api']. La API funciona sin autenticación.

Si no usas Sanctum pero quieres proteger tu API, tienes dos opciones:

Opción 1 - Usar el guard de autenticación integrado:```env THREAT_DETECTION_API_GUARD=auth

**Opción 2: Modificar el middleware directamente:**```php
// config/threat-detection.php
'api' => [
    'enabled' => true,
    'prefix' => 'api/threat-detection',
    'middleware' => ['api', 'auth'],  // or 'auth:your-guard'
],

Para pruebas locales (si Sanctum bloquea el acceso), cambia temporalmente:```php 'middleware' => ['api'], // remove 'auth:sanctum'

> Restaure la autenticación antes de implementar en producción.

### Referencia de Endpoints

| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Listar amenazas (paginadas, filtrables) |
| GET | `/api/threat-detection/threats/{id}` | Detalles de una sola amenaza |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Marcar amenaza como falso positivo |
| GET | `/api/threat-detection/stats` | Estadísticas generales |
| GET | `/api/threat-detection/summary` | Desglose detallado por tipo, nivel, IP |
| GET | `/api/threat-detection/live-count` | Amenazas en la última hora |
| GET | `/api/threat-detection/by-country` | Agrupadas por país |
| GET | `/api/threat-detection/by-cloud-provider` | Agrupadas por proveedor de nube |
| GET | `/api/threat-detection/top-ips` | IPs más infractoras |
| GET | `/api/threat-detection/timeline` | Línea temporal de amenazas (para gráficos) |
| GET | `/api/threat-detection/ip-stats?ip=x.x.x.x` | Estadísticas para una IP específica |
| GET | `/api/threat-detection/correlation` | Análisis de correlación |
| GET | `/api/threat-detection/export` | Exportar a CSV |
| GET | `/api/threat-detection/exclusion-rules` | Listar reglas de exclusión |
| DELETE | `/api/threat-detection/exclusion-rules/{id}` | Eliminar una regla de exclusión |

### Parámetros de Consulta para `/threats`

| Parámetro | Descripción |
|-----------|-------------|
| `keyword` | Buscar en IP, URL, tipo |
| `ip` | Filtrar por dirección IP |
| `level` | Filtrar por nivel de amenaza (`high`, `medium`, `low`) |
| `type` | Filtrar por tipo de amenaza |
| `country` | Filtrar por código de país |
| `is_foreign` | Filtrar IPs extranjeras (`true`/`false`) |
| `cloud_provider` | Filtrar por proveedor de nube |
| `is_false_positive` | Filtrar por estado de falso positivo (`true`/`false`) |
| `date_from` / `date_to` | Filtro de rango de fechas |
| `per_page` | Elementos por página (predeterminado: 20, máximo: 100) |

### Ejemplo de Respuesta de la API

**GET `/api/threat-detection/stats`:**```json
{
  "success": true,
  "data": {
    "total_threats": 847,
    "high_severity": 23,
    "medium_severity": 156,
    "low_severity": 668,
    "unique_ips": 94,
    "foreign_ips": 67,
    "cloud_attacks": 12,
    "today": 34,
    "last_hour": 5
  }
}

Creación de Frontends Personalizados

Vue.js:```javascript async mounted() { const response = await fetch('/api/threat-detection/stats'); this.stats = await response.json();

const threats = await fetch('/api/threat-detection/threats?per_page=20');
this.threats = await threats.json();

}

**React:**```jsx
useEffect(() => {
    fetch('/api/threat-detection/stats')
        .then(res => res.json())
        .then(data => setStats(data));
}, []);

Si tu API usa auth:sanctum, incluye los encabezados de autenticación o configura la autenticación SPA de Sanctum para solicitudes basadas en cookies.


Comandos de Artisan```bash

Check that detection is installed, wired up and actually recording.

Exits non-zero on a real failure, so it works in CI or a deploy step.

php artisan threat-detection:doctor

View threat stats summary in the terminal

php artisan threat-detection:stats

Enrich existing logs with geo-data (country, city, ISP, cloud provider)

Uses the free ip-api.com service (rate-limited to 45 req/min, auto-throttled)

php artisan threat-detection:enrich --days=7

Purge old logs to keep the database clean

php artisan threat-detection:purge --days=30

Export threat IPs for fail2ban (pipe to file or run directly)

php artisan threat-detection:export-fail2ban --level=high --since=24h --min-hits=5 php artisan threat-detection:export-fail2ban --format=plain > /tmp/banlist.txt

Export blocklist in various formats

php artisan threat-detection:export-blocklist --format=nginx > /etc/nginx/blocklist.conf php artisan threat-detection:export-blocklist --format=apache > .htaccess-deny php artisan threat-detection:export-blocklist --format=csv --since=7d

---

## Actuando sobre los Datos (Bloqueo del Lado del Operador)

El paquete nunca bloquea una solicitud — esa es su identidad, no un valor predeterminado. Las exportaciones anteriores
alimentan las capas de aplicación de políticas que ya ejecutas (fail2ban, nginx, un WAF perimetral). Pero algunos despliegues
no tienen tal capa a la que alimentar — hosting compartido, PaaS, contenedores detrás de un balanceador de carga que
no controlas. Para esos casos, el paquete expone sus *decisiones* como ayudantes, y tú escribes el
middleware de aplicación de políticas tú mismo. Misma arquitectura que las exportaciones: **nosotros suministramos la
inteligencia, tú suministras la denegación.**```php
// app/Http/Middleware/EnforceThreatDecisions.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use JayAnta\ThreatDetection\Facades\ThreatDetection;

class EnforceThreatDecisions
{
    public function handle(Request $request, Closure $next)
    {
        $ip = (string) $request->ip();

        // Static operator denylist (config: blocklisted_ips).
        // CIDR supported; whitelisted_ips wins on overlap.
        if (ThreatDetection::isBlocklisted($ip)) {
            abort(403);
        }

        // Volumetric flood: refuse over-threshold clients until the window resets.
        if (ThreatDetection::isDdosThresholdExceeded($ip)) {
            return response('Too Many Requests', 429, [
                'Retry-After' => (string) config('threat-detection.ddos.window', 60),
            ]);
        }

        return $next($request);
    }
}

Antes de aplicar restricciones por IP, configura TrustProxies.

Todo lo anterior depende de $request->ip(). Detrás de un balanceador de carga, CDN o proxy inverso, eso devuelve la IP del cliente solo cuando Laravel sabe qué proxies debe confiar. Si no es así, dos cosas se rompen a la vez: cada solicitud parece venir del proxy, por lo que una entrada en la lista de denegación bloquea todo tu tráfico o nada de él — y peor aún, si la app confía en un encabezado reenviado que no debería, un atacante establece X-Forwarded-For y atraviesa directamente la lista de bloqueo.

Esto importa más aquí que para whitelisted_ips. Una coincidencia incorrecta en la lista blanca solo significa que el paquete escanea una solicitud que podría haber omitido: falla de forma segura. Una lista de denegación usada para rechazar tráfico falla abierta — crees que una dirección está bloqueada cuando no lo está. Revisa app/Http/Middleware/TrustProxies.php (o la llamada trustProxies en bootstrap/app.php en Laravel 11+) antes de confiar en cualquiera de los dos ayudantes para la aplicación de restricciones.

Regístralo globalmente (antes del middleware de detección está bien — los ayudantes leen la configuración y la caché, no dependen del orden del middleware):```php // bootstrap/app.php (Laravel 11+) ->withMiddleware(function ($middleware) { $middleware->prepend(\App\Http\Middleware\EnforceThreatDecisions::class); })

Los helpers:

| Helper | Devuelve | Respaldado por |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | config `blocklisted_ips` (CIDR vía `IpUtils`; la whitelist tiene prioridad) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | config `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | el contador de inundación que mantiene el middleware de detección |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | ese contador frente a `ddos.threshold` |

Notas:

- **La lista de bloqueo es estática y mantenida por el operador.** Nada en el paquete añade
  elementos a ella — ejecuta la misma decisión que tomaría un jail de fail2ban ("leí el panel; este /24
  es hostil"), solo que dentro de la aplicación.
- El contador DDoS cuenta únicamente las peticiones que llegaron a la detección (`skip_paths`, IPs
  en whitelist y entornos deshabilitados nunca se cuentan), y permanece en 0 en drivers de caché donde
  la detección DDoS está deshabilitada (`file`, `database`, `null`).
- Cuando un cliente supera el umbral, también se despacha un [`DdosThresholdExceeded` event](#ddosthresholdexceeded-event)
  — útil para alertar o alimentar una lista de bloqueo externa. No llames a `abort()`
  desde el listener, sin embargo: los listeners se ejecutan dentro del `try/catch` de fail-open
  del middleware de detección, así que el rechazo pertenece a tu propio middleware como se indicó antes.

---

## Seguimiento de Sondas 404

El paquete detecta sondas de reconocimiento — bots que golpean rutas vulnerables conocidas como `/wp-admin`, `/.env` o `/phpmyadmin` en tu sitio que no es WordPress ni phpMyAdmin. Estas no tienen payload malicioso; la ruta en sí es la señal.

Se registran con una etiqueta de tipo `[probe]`, separada de la detección basada en payload. Si una petición de sonda también contiene un payload malicioso, ambas se registran de forma independiente.

Habilitado por defecto con más de 50 rutas de sonda. Personalízalo en `config/threat-detection.php`:```php
'probe_tracking' => [
    'enabled' => true,
    'default_level' => 'medium',
    'paths' => [
        '/wp-admin' => 'WordPress Admin',
        '/wp-admin/*' => 'WordPress Admin',
        '/.env' => 'Environment File',
        '/phpmyadmin' => 'phpMyAdmin',
        '/actuator/*' => 'Spring Actuator',
        // Add your own probe paths...
    ],
],

Deshabilitar con THREAT_DETECTION_PROBE_TRACKING=false.


Campos Seguros (Reducción de Falsos Positivos)

Si campos de formulario específicos contienen legítimamente HTML, palabras clave SQL o código (por ejemplo, editores CMS, entradas de fragmentos de código), puedes excluirlos del escaneo:```php // config/threat-detection.php 'safe_fields' => ['content', 'body', 'html', 'description', 'code'],

Los campos que se listan aquí se eliminan de los parámetros de consulta y del cuerpo de la solicitud — tanto codificado como formulario como JSON (`application/json`) — antes de que se ejecute la detección. Otros campos en la misma solicitud aún se escanean por completo.

### Rutas seguras (conscientes de la ruta, para APIs JSON anidadas)

`safe_fields` coincide con un nombre de clave **en cualquier lugar** donde aparezca. Para APIs JSON anidadas, eso suele ser demasiado amplio: es posible que quieras eximir el valor de un campo específico sin eximir esa clave en todas partes. Usa `safe_paths`, que coincide por **ruta** en notación de puntos y admite comodines `fnmatch`:```php
// config/threat-detection.php
'safe_paths' => ['search.query', 'filters.*.value'],

Por ejemplo, search.query exime el valor de {"search": {"query": "..."}} (un cuadro de búsqueda cuyo texto contiene legítimamente palabras como SELECT), mientras que un campo query en cualquier otro lugar de la solicitud sigue siendo escaneado. Todo lo que no esté listado se escanea exactamente como antes.

Validadores posteriores a la coincidencia (reducción de falsos positivos consciente de sumas de verificación)

Una expresión regular por sí sola no puede expresar todas las restricciones: cualquier secuencia de 12 dígitos coincide con el patrón de Aadhaar, pero un número Aadhaar real también supera la suma de verificación de Verhoeff. Asocia una etiqueta de patrón (predeterminada o personalizada) a un validador con nombre, y una coincidencia de regex solo cuenta como detección cuando al menos un valor coincidente la supera:```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],

Validadores disponibles:

| Validador  | Checksum | Uso típico |
|------------|----------|-------------|
| `verhoeff` | Verhoeff | Números Aadhaar |
| `luhn`     | Luhn     | Números de tarjetas de crédito/débito |

Con la asignación incluida, las marcas de tiempo, los IDs de pedido y los códigos de barras que casualmente tienen 12 dígitos ya no se registran como PII, mientras que los números Aadhaar genuinos sí lo siguen siendo. Si varios valores coinciden y solo uno pasa el checksum, la detección sigue activándose: un número real entre ruido sigue siendo una fuga.

Combina un validador con tu propio patrón para la detección de tarjetas con verificación de checksum:```php
'custom_patterns'    => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],

Un nombre de validador desconocido falla abierto — la coincidencia se cuenta sin validar y se registra una advertencia una sola vez — por lo que un error tipográfico nunca puede deshabilitar silenciosamente un patrón de detección. Las configuraciones publicadas antes de esta función simplemente no tienen la clave y conservan exactamente su comportamiento actual.


Redacción (Detectar No Es Almacenar)

Detectar datos sensibles solía significar almacenarlos. Un formulario de perfil con un número de móvil, PAN y cuenta bancaria activaría tres patrones de PII, y cada una de las tres filas escritas conservaba el cuerpo completo de la solicitud textualmente — retenido durante todo el período de retención, legible por cualquiera con acceso al panel o a la base de datos. Un valor en una cadena de consulta también terminaba en la columna url. El detector se convertía en una segunda copia concentrada de exactamente aquello sobre lo que te advierte.

Activado por defecto desde v1.7.0. Cuando se activa un patrón cuya etiqueta está listada, el valor que coincide se enmascara en la carga útil y la URL almacenadas:``` BODY: {"name":"Jane Doe","mobile":"[REDACTED]","pan":"[REDACTED]","bank_account":"[REDACTED]"}

La alerta, el endpoint, los nombres de los campos y la IP atacante se conservan; solo se elimina el valor. La redacción se ejecuta *después* de la detección, por lo que nada se pierde.```php
// config/threat-detection.php
'redact' => [
    'enabled' => env('THREAT_DETECTION_REDACT', true),
    'mask'    => '[REDACTED]',
    'labels'  => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],

Attack payloads se dejan intactos deliberadamente: una cadena de inyección es evidencia, no un secreto, y enmascararla destruiría la investigación. Solo se modifican las etiquetas que tú listes.

Esto no reemplaza a Safe Fields. Esos detienen que un campo sea escaneado; la redacción te permite seguir escaneando y detener el almacenamiento. Establece THREAT_DETECTION_REDACT=false si necesitas payloads completos para análisis forense.


Autenticación del Panel y la API

El panel y la API admiten guards de autenticación configurables mediante .env:```env

Options: none (default), auth, role, ip

THREAT_DETECTION_DASHBOARD_GUARD=auth

For role-based guard (Spatie compatible):

THREAT_DETECTION_DASHBOARD_GUARD=role THREAT_DETECTION_DASHBOARD_ROLE=admin

For IP-based guard:

THREAT_DETECTION_DASHBOARD_GUARD=ip THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1,10.0.0.0/8

Las mismas opciones están disponibles para las rutas de API con `THREAT_DETECTION_API_GUARD`.

Cuando `guard=none` (valor predeterminado), el paquete registra una advertencia una vez al día para recordarte que configures la autenticación.

La protección **falla de forma segura**: un valor de guard no reconocido (p. ej., un error tipográfico) se deniega con un 403 y una advertencia registrada en lugar de conceder acceso silenciosamente, y `guard=role` deniega (con una advertencia) cuando el modelo de usuario autenticado no tiene un método `hasRole()`.

### Deshabilitar una detección requiere más que acceso de lectura

Marcar una amenaza como falso positivo y eliminar una regla de exclusión silencian un tipo de detección para todos, lo cual es un privilegio distinto al de leer el registro. Esos dos endpoints se verifican contra una protección separada:```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role

Se aplica solo a esas rutas, por lo que la lectura y el panel se comportan exactamente como indica THREAT_DETECTION_API_GUARD. Sin ello, cualquier usuario autenticado de tu aplicación podría desactivar una detección.

Si tu modelo de usuario no tiene hasRole(), usa =auth. Para restaurar el comportamiento anterior a la versión 1.7.0, donde cualquier usuario autenticado podía deshabilitar detecciones, usa =none - threat-detection:doctor mostrará una advertencia mientras esté configurado así.

Nota sobre Panel ↔ API: el panel integrado obtiene sus datos de las rutas de la API utilizando la cookie de sesión del navegador. Si tus rutas de API están protegidas con auth:sanctum, configura la autenticación stateful/SPA de Sanctum (o apunta el panel a un guard autenticado por cookie) para que esas llamadas AJAX estén autorizadas; de lo contrario, el panel se mostrará vacío.


Patrones Personalizados

Añade tus propios patrones de expresión regular de detección en config/threat-detection.php:```php 'custom_patterns' => [ '/your-regex-here/i' => 'Your Threat Label', ],

**Ejemplo: detectar una sonda de endpoint de administración personalizada:**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',

Forma de array (opciones por patrón)

Además de la forma clásica de cadena, el valor de un patrón puede ser un array para tener control total:```php 'custom_patterns' => [ '/\b(?:\d[ -]?){13,19}\b/' => [ 'label' => 'Card Number Detected', // required 'level' => 'high', // low|medium|high — overrides keyword derivation 'contexts' => ['query', 'body'], // query|body|headers — default: all segments 'validator' => 'luhn', // post-match checksum, wins over pattern_validators ], ],

- **`level`** establece el nivel de amenaza directamente en lugar de derivarlo de las palabras clave de `threat_levels` en la etiqueta.
- **`contexts`** restringe el escaneo a segmentos específicos de la solicitud — p. ej., un patrón de tarjeta que solo tiene sentido en el cuerpo deja de coincidir con secuencias de dígitos en las cabeceras.
- **`validator`** nombra una comprobación posterior a la coincidencia en línea (consulta [Validadores posteriores a la coincidencia](#post-match-validators-checksum-aware-false-positive-reduction)); tiene prioridad sobre el mapa de etiquetas `pattern_validators`.

Las entradas de cadenas y matrices se combinan libremente en la misma configuración. Las opciones malformadas **fallan abiertamente** — el patrón sigue escaneando, sin restricciones, y se registra una advertencia — por lo que un error de configuración nunca puede deshabilitar o estrechar silenciosamente una detección.

> **Nota:** Las rutas de sondeo comunes como `/wp-login.php`, `/.env`, `/phpmyadmin` ahora se gestionan automáticamente mediante la función de [Seguimiento de sondeos 404](#404-probe-tracking). No necesitas patrones personalizados para esas.

El nivel de amenaza para cada patrón se determina automáticamente al comparar palabras clave en la etiqueta con la configuración de `threat_levels`:```php
'threat_levels' => [
    'high' => ['XSS', 'SQL Injection', 'SQL DDL', 'SQL DML', 'SQL File', 'SQL Hex', 'RCE', ..., 'Shellshock', 'Spring4Shell', 'PowerShell', 'CRLF', 'Null Byte', 'SSTI', 'Java', 'LDAP', 'XPath', 'PHP assert', ...],
    'medium' => ['Directory Traversal', 'LFI', 'SSRF', 'Sensitive', 'Config', ..., 'Open Redirect', 'LF Injection', 'GraphQL', 'Spring Boot Actuator', ...],
    'low' => ['User-Agent', 'JS Redirect', 'SEO Bot', 'Empty', 'Rate', 'Command-line Downloader', 'DNS Rebinding'],
],

Si la etiqueta no coincide con ninguna palabra clave, la amenaza se establece por defecto en severidad low.

Los patrones regex inválidos se omiten automáticamente y se registran como advertencias: no harán fallar tu aplicación.


Uso de la Fachada

Para acceso programático a los datos de amenazas fuera del middleware:```php use JayAnta\ThreatDetection\Facades\ThreatDetection;

// Get attack statistics for a specific IP $stats = ThreatDetection::getIpStatistics('192.168.1.1');

// Detect coordinated attacks (multiple IPs targeting same URL within 15 minutes) $attacks = ThreatDetection::detectCoordinatedAttacks(15, 3);

// Detect attack campaigns (same threat type from 5+ IPs in last 24 hours) $campaigns = ThreatDetection::detectAttackCampaigns(24);

// Get a summary of all correlation data $summary = ThreatDetection::getCorrelationSummary();

// Operator-side decision helpers (see "Acting on the Data") $blocked = ThreatDetection::isBlocklisted('203.0.113.7'); // static denylist, CIDR, whitelist wins $trusted = ThreatDetection::isWhitelisted('10.0.0.5'); $count = ThreatDetection::ddosRequestCount('203.0.113.7'); // requests in the current DDoS window $flooded = ThreatDetection::isDdosThresholdExceeded('203.0.113.7');

---

## Puesta en Producción

El paquete es pasivo por diseño: nunca bloquea, rechaza ni altera una solicitud, y el middleware de detección envuelve todo su cuerpo en `try/catch`, por lo que un fallo de detección nunca puede romper tu aplicación. Incluye valores predeterminados sensatos y no necesita servicios externos para funcionar. Antes de salir a producción, vale la pena revisar esta breve lista de verificación:

1. **Protege el panel y la API.** Ambos usan `guard = none` por defecto para una primera ejecución sin configuración, y registran una advertencia diaria mientras estén desprotegidos. Antes de producción, establece un guard: `THREAT_DETECTION_DASHBOARD_GUARD` y `THREAT_DETECTION_API_GUARD` (`auth`, `role` o `ip`). Un valor no reconocido o un guard `role` en un modelo de usuario sin `hasRole()` ahora **falla de forma segura** (403), por lo que un error tipográfico no expondrá datos silenciosamente. Deshabilitar una detección se controla por separado con `THREAT_DETECTION_API_WRITE_GUARD`, que por defecto es `role`. Consulta [Autenticación del Panel y la API](#dashboard-and-api-authentication).
2. **Ejecuta las migraciones** (`vendor:publish --tag=threat-detection-migrations && migrate`). Volver a publicar es seguro: las migraciones ya publicadas se omiten.
3. **Elige un modo de detección.** `balanced` (predeterminado) se adapta a la mayoría de las aplicaciones; usa `relaxed` para sitios con mucho contenido, `strict` para superficies de alta seguridad. Ajusta con `content_paths`, `safe_fields` y `min_confidence`: consulta [Reducción de Falsos Positivos](#reducing-false-positives).
4. **Revisa los patrones regionales de PII / personalizados.** Los valores predeterminados están centrados en India (Aadhaar, PAN, IFSC) y los patrones numéricos amplios (por ejemplo, cuentas bancarias) pueden coincidir con IDs numéricos largos fuera de las rutas de autenticación. Reemplaza o recorta `custom_patterns` para tu región y aplicación, y añade rutas con mucho contenido a `auth_paths` / `content_paths`.
5. **Activa la retención** si esperas volumen: `THREAT_DETECTION_RETENTION=true` (purga automática mediante el programador). Requiere que el programador de Laravel (`schedule:run`) esté controlado por cron.
6. **Extras opcionales, todos desactivados por defecto:** alertas de Slack (`THREAT_DETECTION_NOTIFICATIONS`), enriquecimiento geográfico (`php artisan threat-detection:enrich` — la única función que realiza una llamada saliente, al gratuito ip-api.com) y escrituras en cola (`THREAT_DETECTION_QUEUE` — actívalo solo si ya ejecutas un worker de cola; de lo contrario, las escrituras son síncronas y no necesitan Redis).

No se requieren Redis, worker de cola ni llamadas de red salientes para la detección y el registro principales.

---

## Reducción de Falsos Positivos

El paquete proporciona múltiples herramientas para reducir los falsos positivos. Usa la que se adapte a tu situación:

### Campos Seguros y Rutas Seguras

Excluye un campo del escaneo por completo, ya sea por nombre en todas partes (`safe_fields`) o por ruta con notación de puntos para JSON anidado (`safe_paths`). Es el enfoque más simple y el más contundente: el campo se omite, por lo que no se ejecuta ninguna detección sobre él.

Detalles completos y ejemplos: [Campos Seguros](#safe-fields-false-positive-reduction).

### Supresión de Rutas de Contenido

Si tienes editores de CMS, formularios de publicaciones de blog o secciones de comentarios donde los usuarios envían contenido enriquecido, esas rutas suelen provocar falsos positivos (por ejemplo, una publicación de blog que contiene ejemplos de código `<script>`). Añade esas rutas para suprimir alertas de baja/media gravedad:```php
// config/threat-detection.php
'content_paths' => [
    'admin/posts/*',
    'admin/pages/*',
    'blog/*/edit',
    'comments',
],

En estas rutas, solo se registran amenazas de alta severidad.

Reporte de Falsos Positivos

Haz clic en el botón FP en cualquier amenaza del panel para marcarla como falso positivo. Esto:

  1. Marca la amenaza como is_false_positive = true
  2. Crea automáticamente una regla de exclusión para que amenazas similares de la misma URL/tipo se supriman en el futuro

Gestiona las reglas de exclusión mediante la API:```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}

### Puntuación de Confianza

Cada amenaza recibe una puntuación de confianza (0-100) basada en:
- Número de coincidencias de patrones en la misma solicitud
- Gravedad del patrón coincidente
- Dónde se encontró el patrón (cadena de consulta > cabeceras > cuerpo)
- Si el user-agent coincide con una herramienta de ataque conocida
- Modo de detección actual

Las amenazas por debajo del umbral de confianza para tu modo de detección no se registran (consulta [Modos de Detección](#modos-de-detección)).

---

## Tipos de Ataques Detectados

| Categoría | Ejemplos |
|----------|---------|
| **Inyección SQL** | UNION, booleana, basada en tiempo, codificación CHAR, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), operaciones de archivo (INTO OUTFILE, LOAD_FILE), enumeración ORDER BY, cadenas hexadecimales, UNHEX |
| **Inyección NoSQL** | Operadores de MongoDB $ne, $gt, $regex, $where |
| **XSS** | Etiquetas de script, manejadores de eventos SVG (`<svg onload=`), manejadores de eventos HTML (`<body onload=`, `<img onerror=`), expresiones CSS, URIs JavaScript, manipulación del DOM |
| **Ejecución de Código** | Funciones de shell RCE, deserialización PHP, deserialización Java (bytes mágicos base64 + hex), inyección de plantillas (Blade, JSP, ASP, Jinja2, Velocity), eval(), decodificación base64, assert() de PHP, create_function(), preg_replace /e |
| **SSTI** | Sondeos matemáticos (`{{7*7}}`), import/config de Jinja2, plantillas Velocity, Lenguaje de Expresión |
| **Inyección de Comandos** | Linux (funciones de shell, cadenas de comandos, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Acceso a Archivos** | Traversal de directorios, protocolos LFI/RFI, sondeos de archivos sensibles (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), metadatos AWS/GCP, IPs privadas, localhost codificado en hex/decimal, rebinding DNS (xip.io, nip.io, sslip.io) |
| **Inyección LDAP** | Manipulación de filtros LDAP, inyección OR |
| **Inyección XPath** | Selectores de atributos, funciones XPath (contains, substring) |
| **Inyección CRLF / Cabeceras** | CRLF codificado en URL (`%0d%0a`), inyección LF, inyección de byte nulo |
| **Ataques de Protocolo** | Contrabando de solicitudes HTTP (CL+TE), inyección SSI |
| **Exploits CVE** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), RCE PHPUnit (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Seguimiento de Sondeos** | WordPress (`/wp-admin`, `/wp-login.php`), archivos de configuración (`/.env`, `/.git`), herramientas de bases de datos (`/phpmyadmin`), sondeos de tecnología (`.asp`, `.jsp`), actuator de Spring, documentación Swagger/API - más de 50 rutas |
| **Escáneres** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei, y más de 20 otros (53 en total) |
| **Raspadores de IA** | GPTBot, ClaudeBot, ChatGPT, ByteSpider, Cohere, Common Crawl |
| **Navegadores Headless** | HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright |
| **Bots** | Scripts Python, clientes HTTP Go, cURL, wget, AhrefsBot, SEMRushBot, user agents vacíos |
| **Autenticación** | Detección de fuerza bruta, fugas de tokens, exposición de contraseñas, exposición de ID de sesión |
| **DDoS** | Detección de solicitudes excesivas basadas en tasa |
| **Evasión** | Inserción de comentarios SQL, doble codificación URL, codificación de entidades HTML, escapes Unicode, IIS Unicode, escapes hex |
| **Otros** | Introspección GraphQL, contaminación de prototipos, redirección abierta, XXE, webshells, minería de criptomonedas, detección de PII |

---

## Ejecución del Conjunto de Pruebas```bash
composer test

El paquete incluye 335 pruebas (856 aserciones) que cubren patrones de detección, comportamiento del middleware, endpoints de API, puntuación de confianza, reglas de exclusión, detección de DDoS, resistencia a evasión, patrones CVE, inyección LDAP/XPath/SSTI, detección de bots/escáneres, seguimiento de sondas, comandos de exportación, autenticación del panel, campos seguros, optimizaciones de rendimiento y verificación completa de extremo a extremo HTTP a base de datos.


Licencia

Licencia MIT. Consulta LICENSE para más detalles.

Contribuciones

¡Las contribuciones son bienvenidas! Por favor, envía un Pull Request.

Créditos

Categorías