Retour aux mises à jour
New releaseJul 23, 2026

laravel-threat-detection v1.3.1

Système de détection de menaces passif pour Laravel. Enregistre les injections SQL, XSS, RCE, les bots scanners, les sondes 404 et plus de 175 schémas d'attaque. Tableau de bord intégré, export fail2ban, alertes Slack et API REST. IDS, pas WAF.

Partager

Latest Version Tests Total Downloads PHP Version License

Détection de menaces Laravel

Détection d'intrusion passive pour Laravel — voyez chaque injection SQL, XSS, scanner et sonde de bot qui frappe votre application, consignée avec son contexte complet. C'est un IDS, pas un WAF : il ne bloque, ne filtre ni ne modifie jamais une requête.

Threat Detection Dashboard — stats, 7-day timeline, live threat log, top offending IPs, and threats by country

Intégrez-le dans n'importe quelle application Laravel 10–13 et il commence à analyser chaque requête HTTP à la recherche de 150+ schémas d'attaque, en attribuant un score de confiance à chaque correspondance et en l'écrivant dans votre base de données — avec un tableau de bord intégré, des alertes Slack, un enrichissement géographique et des exports fail2ban/listes noires. Aucune requête n'est jamais bloquée. Pensez caméra de sécurité, pas serrure : il vous montre exactement qui sonde vos routes, à quelle fréquence et avec quelles techniques.

Extrait d'une application en production et éprouvé sur du trafic réel. 335 tests, aucune dépendance d'exécution en dehors de Laravel lui-même, et aucune connexion internet requise pour la détection.

Commencez en moins d'une minute```bash

composer require jayanta/laravel-threat-detection php artisan vendor:publish --tag=threat-detection-migrations php artisan migrate

Ajoutez ensuite le middleware à votre groupe `web` (une ligne dans `bootstrap/app.php` sur Laravel 11+,
ou `app/Http/Kernel.php` sur Laravel 10) — extrait complet dans [Démarrage rapide](#quick-start) ci-dessous.
Et voilà ; la détection est active.```bash
php artisan threat-detection:doctor   # confirms it is actually recording

Où cela s'insère : IDS vs WAF vs edge

Ce paquet est un IDS applicatif passif — il observe et enregistre, il ne bloque pas. Il est conçu pour se placer aux côtés d'un WAF ou d'un service edge, pas pour le remplacer. Chaque couche voit quelque chose que les autres ne voient pas :

Ce paquet (IDS applicatif)WAF (mod_security, Cloudflare WAF)Edge / CDN (Cloudflare)
Bloque les requêtes malveillantes❌ journaux uniquement
Contexte applicatif complet (route exacte, charge utile décodée, utilisateur authentifié)⚠️ partiel
Tableau de bord intégré + journal des menaces dans votre base de données⚠️ variable⚠️ edge uniquement
Détections spécifiques à l'application (p. ex. Aadhaar / PAN / IFSC PII)✅ motifs personnalisés
Fonctionne hors ligne / aucun service externe⚠️ dépend
Arrête le trafic avant qu'il n'atteigne votre application✅ edge
Installationune commande composer requiremoyen–élevéfaible–moyen
Coûtgratuit, MITvariableoffre gratuite + payant

En bref : un edge/WAF est votre verrou sur la porte ; c'est la caméra de sécurité à l'intérieur, avec le contexte applicatif pour vous dire exactement ce qui est tenté sur quelle route, par qui, et à quelle fréquence. Utilisez-le pour alimenter de vraies décisions — bans fail2ban, limites de débit, blocage géographique — avec des données que votre couche edge ne voit jamais.

Ce qu'il n'est délibérément PAS

  • Pas un WAF. Il ne bloque, ne filtre ni ne modifie jamais une requête. Utilisez Cloudflare, mod_security, ou un vrai WAF pour l'application des règles. (Pas de couche edge à qui confier la tâche ? Les helpers côté opérateur exposent les décisions du paquet afin que vous puissiez écrire votre propre middleware de blocage en cinq lignes — le code d'application des règles reste le vôtre, pas celui du paquet.)
  • Pas un substitut à l'écriture de code sécurisé. Les requêtes paramétrées, la validation des entrées et l'échappement des sorties sont vos véritables défenses. Ce paquet suppose que votre code est déjà sécurisé et vous offre de la visibilité, pas une protection.
  • Pas un service edge. Si vous pouvez mettre Cloudflare devant, faites-le — puis ajoutez ceci pour le détail au niveau application que les services edge ne voient pas.

Alors qu'en faites-vous concrètement ?

La question la plus courante à propos d'un détecteur qui ne bloque jamais. Quatre réponses, par ordre croissant d'effort :

Vous voulezUtilisezEffort
Voir ce qui vous frappeLe tableau de bord ou threat-detection:statsaucun, c'est déjà en cours
Bannir les récidivistes au niveau du pare-feuthreat-detection:export-fail2ban — à mettre dans une cronune ligne
Refuser au niveau du serveur webthreat-detection:export-blocklist → directives nginx/apacheune ligne
Refuser les requêtes dans l'applicationHelpers côté opérateurisBlocklisted(), isDdosThresholdExceeded()~10 lignes de votre propre middleware
Réagir en temps réelL'événement ThreatDetected — Telegram, SIEM, PagerDutyun listener

Le paquet fournit l'intelligence ; vous fournissez le refus. Cette séparation est délibérée — le code d'application des règles qui vit dans votre application est un code que vous pouvez lire, tester et désactiver, et cela signifie qu'un bug de détection ne peut jamais faire tomber votre site.


Prérequis

  • PHP 8.2+ (Laravel 13 nécessite PHP 8.3+)
  • Laravel 10.x, 11.x, 12.x ou 13.x
  • Toute base de données prise en charge par Laravel (MySQL, PostgreSQL, SQLite, SQL Server)
  • Tout pilote de cache - aucun Redis ni worker de file d'attente requis. Redis/Memcached n'est que recommandé pour activer la vérification DDoS optionnelle (qui se désactive automatiquement sur les pilotes non atomiques). Les écritures en file d'attente sont optionnelles et désactivées par défaut.

Fonctionnement

  1. Un middleware analyse chaque requête HTTP entrante
  2. La requête est vérifiée par rapport à 158 motifs regex couvrant l'injection SQL, XSS, RCE, la traversée de fichiers, SSRF, LDAP, XPath, SSTI, et plus
  3. Si un motif de menace correspond, un enregistrement est écrit dans votre table threat_logs avec l'IP, l'URL, le type de menace, le niveau de gravité et un score de confiance
  4. En option, une alerte Slack est envoyée pour les menaces de haute gravité
  5. La requête se poursuit normalement - rien n'est bloqué

Aucune connexion Internet n'est nécessaire pour la détection.


Démarrage rapide

1. Installer le paquet```bash

composer require jayanta/laravel-threat-detection

### 2. Publier les migrations et les exécuter

> **Cette étape est requise.** Sans elle, le package détectera les menaces mais ne pourra pas les stocker dans la base de données. Si vous ignorez cette étape, votre table `threat_logs` n'existera pas et toutes les détections seront silencieusement perdues (vous ne verrez que des erreurs dans `storage/logs/laravel.log`).```bash
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Cela crée deux tables: threat_logs (stocke les menaces détectées) et threat_exclusion_rules (stocke les règles de faux positifs).

Vérifiez que les tables ont été créées:```bash php artisan migrate:status

Recherchez `create_threat_logs_table`, `add_confidence_to_threat_logs_table` et `create_threat_exclusion_rules_table` -  toutes doivent afficher `Ran`.

### 3. Enregistrer le middleware

Le middleware est ce qui analyse les requêtes. Vous devez l'ajouter à votre groupe de middleware `web`.

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

Comment vérifier votre version de Laravel : Exécutez php artisan --version dans votre terminal.

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

### 4. (Facultatif) Publier le fichier de configuration```bash
php artisan vendor:publish --tag=threat-detection-config

Le package fonctionne avec des valeurs par défaut raisonnables. La publication de la configuration vous permet de personnaliser les modèles de détection, les modes de sensibilité, les notifications Slack, etc. Si vous ignorez cette étape, tout fonctionne quand même.

C'est tout. Votre application détecte désormais les menaces.


Vérifier que cela fonctionne

Après l'installation, déclenchez une menace de test et confirmez qu'elle a été journalisée.

Étape 1: Démarrez votre application```bash

php artisan serve

### Étape 2 : Ouvrez une URL de test dans votre navigateur

Ajoutez un paramètre de requête malveillant à **n'importe quelle route existante** de votre application (votre page d'accueil, une page produit, etc.). Par exemple :

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

XSS (Cross-Site Scripting):``` http://localhost:8000/?q=

**Traversée de répertoire:**```
http://localhost:8000/?file=../../etc/passwd

RCE (Exécution de code à distance):``` http://localhost:8000/?cmd=system('ls -la')

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

Injection de commandes Windows:``` http://localhost:8000/?cmd=powershell -c whoami

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

Utilisez une route qui existe réellement dans votre application (comme /). Si l'URL renvoie une 404, le middleware peut ne pas avoir été exécuté.

Étape 3: Vérifiez que les menaces ont été consignées

Option A - Commande Artisan (la plus rapide):```bash php artisan threat-detection:stats

Vous devriez voir un tableau avec `Total Threats`, les décomptes de sévérité et les principales IP.

**Option B -  Tinker:**```bash
php artisan tinker
DB::table('threat_logs')->latest()->take(5)->get(['ip_address', 'type', 'threat_level', 'confidence_score']);

Option C - Fichier de journalisation Laravel: Chaque menace détectée est écrite comme un avertissement dans storage/logs/laravel.log :``` [high] Threat Detected: [middleware] SQL Injection UNION from 127.0.0.1 (http://localhost:8000/?q=...) [confidence: 50%]

### À savoir lors des tests

| Comportement | Explication |
|----------|-------------|
| Une même menace n'est journalisée qu'une fois toutes les 5 minutes | Déduplication : la même IP et le même type de menace sont mis en cache pendant 5 minutes. Utilisez **différents types d'attaque** pour chaque test, ou attendez entre les tests. |
| Les requêtes `curl` déclenchent une détection supplémentaire | L'utilisation de `curl` journalise également une détection de user-agent "cURL Command" (faible sévérité). C'est attendu : le paquet détecte les outils automatisés. |
| Le paquet ne bloque jamais les requêtes | Votre application continue de fonctionner normalement. La détection est passive. |
| Aucune configuration Slack requise | Les notifications sont désactivées par défaut. |
| Aucune connexion internet requise | La détection de base est 100 % locale. Seule la commande facultative `threat-detection:enrich` appelle une API externe pour les données géographiques. |

### Dépannage

**Commencez ici — une seule commande résout la plupart de ces problèmes :**```bash
php artisan threat-detection:doctor

Il vérifie les éléments qui font échouer la détection silencieusement — là où le tableau de bord reste vide, ce qui ressemble exactement à "aucune attaque" — et affiche la correction exacte pour chacun. Il renvoie un code de sortie non nul en cas de véritable échec, il est donc sûr de l'exécuter dans un CI ou une étape de déploiement.``` 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.

Ce qu'il couvre : la détection activée pour cet environnement ; chaque colonne dont le writer a besoin (une colonne manquante rejette **toutes** les menaces) ; les colonnes du tableau de bord / de l'API ; la table des règles d'exclusion ; que le middleware soit réellement connecté à une route ou à un groupe ; la configuration publiée qui précède cette version ; les motifs personnalisés qui masquent les motifs intégrés ; un pilote de cache incapable de faire le comptage DDoS ; et un tableau de bord ou une API laissé ouvert sans authentification.

**« J'ai testé mais `threat-detection:stats` affiche zéro menace » / « Les menaces ne sont pas stockées dans la base de données »**

Si le doctor a réussi, l'installation est correcte et le problème vient de la requête de test elle-même. Trois choses qu'il ne peut pas vérifier pour vous :

| Vérification | Comment vérifier |
|-------|---------------|
| L'IP n'est pas dans la liste blanche | Si vous avez ajouté `THREAT_DETECTION_WHITELISTED_IPS` dans `.env`, retirez-le pendant les tests |
| Utiliser une route existante | L'URL de test doit correspondre à une route réelle (par ex. `/`). Une 404 signifie que le middleware n'a jamais été exécuté |
| Cache de déduplication | Même IP + même type d'attaque est mis en cache pendant 5 minutes - essayez un type d'attaque différent |

> Exécuter `php artisan migrate` seul ne suffit jamais : les fichiers de migration
> vivent dans le package et doivent d'abord être publiés dans le répertoire `database/migrations/` de votre application. Le doctor affiche la commande exacte lorsque c'est le problème.

**« L'API renvoie 401 Unauthorized »**

Voir [Authentification API](#api-authentication) ci-dessous.

**« Le tableau de bord affiche 404 »**

Le tableau de bord est désactivé par défaut. Ajoutez `THREAT_DETECTION_DASHBOARD=true` à `.env` et videz le cache des routes :```bash
php artisan route:clear

Fonctionnalités

  • 150+ schémas de détection - Injection SQL (UNION, DDL, DML, opérations sur fichiers), XSS (script, SVG, expression CSS), RCE, traversée de répertoire, SSRF, XXE, Log4Shell, injection NoSQL, injection de commandes (Linux + Windows), injection LDAP, injection XPath, SSTI, injection CRLF, désérialisation Java, et plus encore
  • 83 signatures de bots/scanners - SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, et plus de 70 autres signatures de scanners et de bots
  • Détection des scrapers IA - GPTBot, ClaudeBot, ByteSpider, Common Crawl, et autres bots d'entraînement IA
  • Détection des navigateurs headless - HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright
  • Suivi des sondes 404 - Détecte les sondes de reconnaissance atteignant des chemins vulnérables connus (/wp-admin, /.env, /phpmyadmin, /actuator, etc.) avec plus de 50 chemins de sonde par défaut
  • Surveillance DDoS - Détection de seuils basée sur le débit avec fenêtres configurables
  • Score de confiance - Chaque menace obtient un score de confiance de 0 à 100 basé sur le nombre de schémas, le contexte et les signaux
  • Résistance à l'évasion - Le pipeline de normalisation neutralise l'insertion de commentaires SQL, le double encodage URL, l'encodage d'entités HTML, les échappements Unicode et les échappements hexadécimaux avant la correspondance de schémas
  • Détection de CVE - Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
  • Détection contextuelle - Les schémas trouvés dans les chaînes de requête obtiennent un score plus élevé que ceux du corps de la requête
  • Analyse du corps de requête - Le corps des requêtes encodées en formulaire et JSON (application/json) est inspecté
  • Champs sûrs - Exclure des champs de formulaire spécifiques de l'analyse (pour les éditeurs CMS, les champs de code, les champs de recherche)
  • Signalement des faux positifs - Marquer des menaces comme faux positifs depuis le tableau de bord ; crée automatiquement des règles d'exclusion
  • Trois modes de détection - strict, balanced (par défaut) et relaxed - sensibilité réglable
  • Suppression par chemin de contenu - Autoriser (whitelist) les chemins CMS/blog pour supprimer les alertes faibles/moyennes provenant de contenu riche
  • Détection des données personnelles (PII) - Schémas d'exposition de données sensibles (configurables par région)
  • Enrichissement géographique - Identification du pays, de la ville, du FAI et du fournisseur cloud via une API gratuite
  • Alertes Slack - Notifications en temps réel pour les menaces de gravité élevée (fonctionne sur Laravel 10 et 11+)
  • Tableau de bord intégré - Tableau de bord Blade en mode sombre (Alpine.js + Tailwind CDN, zéro étape de compilation)
  • Protection d'authentification du tableau de bord - Authentification configurable pour le tableau de bord et l'API (aucune, auth, rôle ou par IP)
  • 15 endpoints API - API REST complète pour créer des tableaux de bord personnalisés Vue/React/mobile
  • Export Fail2ban - Exporter les IP détectées au format compatible fail2ban ou en liste de blocage simple
  • Export de liste de blocage - Exporter les IP au format nginx deny, Apache deny, CSV ou simple
  • Export CSV - Export des journaux de menaces en un clic (jusqu'à 10 000 lignes)
  • Analyse de corrélation - Détecter les attaques coordonnées et les campagnes d'attaque entre les IP
  • Performances optimisées - Chargement paresseux des schémas par catégorie (les regex ne s'exécutent que pour les catégories d'attaque pertinentes), abandon précoce pour les requêtes propres, court-circuit des UA de navigateur (saute plus de 70 vérifications pour les navigateurs normaux), recherche par hachage des chemins de sonde, insertions DB par lots, nombre maximal de détections configurable par requête
  • Indépendant de la base de données - MySQL, PostgreSQL, SQLite, SQL Server
  • Zéro configuration - Fonctionne immédiatement avec des paramètres par défaut judicieux
  • Sûr par conception - Le middleware intercepte ses propres erreurs. Si la détection échoue, votre application continue de fonctionner. Les requêtes ne sont jamais bloquées.

Configuration

Le package fonctionne sans aucune modification de .env. Toutes les valeurs ci-dessous sont facultatives - ajoutez-les uniquement si vous souhaitez remplacer les valeurs par défaut.```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

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

### Modes de détection

| Mode | Seuil de confiance | Comportement |
|------|--------------------|--------------|
| `strict` | 0 (journalise tout) | Tous les patterns actifs, seuils les plus bas. Capture tout mais peut signaler du trafic légitime. |
| `balanced` | 10 | Par défaut. Score de confiance actif, seuils standards. Bon pour la plupart des applications. |
| `relaxed` | 40 | Seuls les patterns à haute sévérité déclenchent. Idéal pour les sites à fort contenu avec de fréquents faux positifs. |

### Environnements activés

Par défaut, la détection s'exécute dans `production`, `staging` et `local`. Pour modifier, publiez la configuration et éditez :```php
'enabled_environments' => ['production', 'staging', 'local'],

Pour désactiver la détection dans votre suite de tests, définissez APP_ENV=testing (pas dans la liste ci-dessus) ou ajoutez à votre phpunit.xml :```xml

### Référence de configuration

Publiez le fichier de configuration pour voir toutes les options disponibles :```bash
php artisan vendor:publish --tag=threat-detection-config

Sections clés de configuration : skip_paths (chemins à ignorer), only_paths (mode liste blanche), auth_paths (détection intelligente des routes de connexion), content_paths (masquer les alertes non élevées), safe_fields (exclure des champs spécifiques de l’analyse), safe_paths (exclusion de champs selon le chemin pour JSON imbriqué), probe_tracking (détection des 404 de sondage), context_weights (multiplicateurs de score), threat_levels (mappage des mots-clés de sévérité), api_route_filtering (masquer les alertes faibles/moyennes sur les routes API), queue (traitement asynchrone), retention (purge automatique), max_detections_per_request (limite de performance), dashboard.guard / api.guard (mode d’authentification).

Liste blanche de routes (only_paths)

Si votre application possède de nombreuses routes mais que seules quelques-unes vous intéressent, utilisez only_paths pour analyser uniquement ces routes. Toutes les autres routes sont automatiquement ignorées – aucun surcoût middleware du tout.```php // config/threat-detection.php 'only_paths' => [ 'admin/', 'api/', 'login', 'register', ],

Leave empty (default) to scan all routes (subject to `skip_paths`). When both are configured, `only_paths` is checked first, then `skip_paths` applies within the matched set.

### Queue Support

By default, threat logging happens synchronously in the request cycle. For high-traffic apps, you can offload DB writes and Slack notifications to a queue:

---

Laissez vide (par défaut) pour scanner toutes les routes (sous réserve de `skip_paths`). Lorsque les deux sont configurés, `only_paths` est vérifié en premier, puis `skip_paths` s'applique à l'ensemble correspondant.

### Prise en charge des files d'attente

Par défaut, la journalisation des menaces se fait de manière synchrone dans le cycle de requête. Pour les applications à fort trafic, vous pouvez décharger les écritures en base de données et les notifications Slack vers une file d'attente :```env
THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=threat-logs

Ceci envoie une tâche StoreThreatLog (3 nouvelles tentatives, backoff 10s/30s). La détection se fait toujours en temps réel - seul l'écriture est différée.

Purge automatique (politique de rétention)

Supprime automatiquement les anciens journaux de menaces selon un planning quotidien :```env THREAT_DETECTION_RETENTION=true THREAT_DETECTION_RETENTION_DAYS=90

Requires Laravel's scheduler to be running (`php artisan schedule:run`). Runs daily at 02:00 via `threat-detection:purge`.

### Événement ThreatDetected

Toute menace confirmée déclenche un événement `ThreatDetected` que vous pouvez écouter :```php
// app/Providers/EventServiceProvider.php
use JayAnta\ThreatDetection\Events\ThreatDetected;

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

L'événement transporte $threatLog (tableau complet de la ligne de base de données), $ipAddress, et $threatLevel. Utilisez-le pour déclencher des actions personnalisées - envoyer des alertes Telegram, mettre à jour une liste de blocage, alimenter un SIEM, etc.

Événement DdosThresholdExceeded

Lorsqu'un client dépasse le seuil DDoS configuré (ddos.threshold requêtes dans ddos.window secondes), un événement DdosThresholdExceeded est déclenché en même temps que l'entrée du journal des menaces :```php use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;

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

L'événement contient `$ipAddress`, `$requestCount`, `$threshold` et `$windowSeconds`. Il est
limité à une fois par IP par fenêtre de déduplication (même limite que la ligne de journal), donc un flot ne peut pas
submerger vos écouteurs. Utilisez-le pour les alertes ou pour alimenter un stock de bannissement externe; pour *refuser*
les clients dépassant le seuil, utilisez `ThreatDetection::isDdosThresholdExceeded($ip)` depuis votre propre
middleware à la place — voir [Agir sur les données](#acting-on-the-data-operator-side-blocking).

---

## Notifications Slack

Les alertes Slack sont désactivées par défaut. Pour activer :```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Seules les menaces de gravité élevée déclenchent des notifications par défaut (configurable via notify_levels dans la configuration).

Laravel 10: Utilise la classe de notification intégrée SlackMessage. Aucun paquet supplémentaire n'est nécessaire.

Laravel 11+: Le canal Slack intégré a été supprimé. Le paquet détecte automatiquement cela et envoie des webhooks HTTP POST bruts à votre URL Slack. Aucun paquet supplémentaire n'est nécessaire. Si vous préférez le canal de notification complet, installez :```bash composer require laravel/slack-notification-channel

---

## Tableau de bord

Le package est livré avec un tableau de bord en mode sombre intégré (Alpine.js + Tailwind CDN -  aucune étape de build requise).```
+-------------------------------------------------------------------------+
|  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                                         |
+-------------------------------------------------------------------------+

Activer le tableau de bord

Ajoutez à .env:```env THREAT_DETECTION_DASHBOARD=true

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

### Accéder pendant le développement local

Le tableau de bord utilise par défaut le middleware `['web', 'auth']`, donc les utilisateurs doivent être connectés. Si votre application n'a pas encore d'authentification, restreignez-le à votre propre machine à la place :```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

Toutes les options de garde, et la garde séparée sur les points de terminaison qui désactivent les détections, sont couvertes dans Tableau de bord et authentification de l'API.

Si le tableau de bord affiche des données vides, la page a chargé mais ses appels API n'ont pas abouti. Voir Authentification de l'API.


Points de terminaison de l'API

Le package fournit 15 points de terminaison REST pour créer des tableaux de bord personnalisés ou des intégrations.

Authentification de l'API

Les routes API utilisent le middleware auth:sanctum par défaut. Le package gère cela de manière transparente :

  • Sanctum installé : l'API exige une authentification via les jetons Sanctum ou l'authentification de session SPA.
  • Sanctum non installé : le package détecte automatiquement que Sanctum est manquant et se rabat sur ['api'] uniquement. L'API fonctionne sans authentification.

Si vous n'utilisez pas Sanctum mais souhaitez protéger votre API, vous avez deux options :

Option 1 - Utilisez la garde d'authentification intégrée :```env THREAT_DETECTION_API_GUARD=auth

**Option 2 -  Modifier le middleware directement :**```php
// config/threat-detection.php
'api' => [
    'enabled' => true,
    'prefix' => 'api/threat-detection',
    'middleware' => ['api', 'auth'],  // or 'auth:your-guard'
],

Pour les tests locaux (si Sanctum bloque l'accès), modifiez temporairement :```php 'middleware' => ['api'], // remove 'auth:sanctum'

> Rétablissez l'authentification avant le déploiement en production.

### Référence des points de terminaison

| Méthode | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Liste des menaces (paginée, filtrable) |
| GET | `/api/threat-detection/threats/{id}` | Détails d'une menace individuelle |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Marquer la menace comme faux positif |
| GET | `/api/threat-detection/stats` | Statistiques générales |
| GET | `/api/threat-detection/summary` | Ventilation détaillée par type, niveau, IP |
| GET | `/api/threat-detection/live-count` | Menaces de la dernière heure |
| GET | `/api/threat-detection/by-country` | Groupées par pays |
| GET | `/api/threat-detection/by-cloud-provider` | Groupées par fournisseur cloud |
| GET | `/api/threat-detection/top-ips` | Principales IP fautives |
| GET | `/api/threat-detection/timeline` | Chronologie des menaces (pour graphiques) |
| GET | `/api/threat-detection/ip-stats?ip=x.x.x.x` | Statistiques pour une IP spécifique |
| GET | `/api/threat-detection/correlation` | Analyse de corrélation |
| GET | `/api/threat-detection/export` | Exporter en CSV |
| GET | `/api/threat-detection/exclusion-rules` | Liste des règles d'exclusion |
| DELETE | `/api/threat-detection/exclusion-rules/{id}` | Supprimer une règle d'exclusion |

### Paramètres de requête pour `/threats`

| Paramètre | Description |
|-----------|-------------|
| `keyword` | Recherche dans l'IP, l'URL, le type |
| `ip` | Filtrer par adresse IP |
| `level` | Filtrer par niveau de menace (`high`, `medium`, `low`) |
| `type` | Filtrer par type de menace |
| `country` | Filtrer par code pays |
| `is_foreign` | Filtrer les IP étrangères (`true`/`false`) |
| `cloud_provider` | Filtrer par fournisseur cloud |
| `is_false_positive` | Filtrer par statut de faux positif (`true`/`false`) |
| `date_from` / `date_to` | Filtre de plage de dates |
| `per_page` | Éléments par page (défaut : 20, max : 100) |

### Exemple de réponse 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
  }
}

Créer des frontends personnalisés

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 votre API utilise auth:sanctum, incluez les en-têtes d'authentification ou configurez l'authentification SPA Sanctum pour les requêtes basées sur les cookies.


Commandes 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

---

## Agir sur les données (blocage côté opérateur)

Le paquet ne bloque jamais une requête — c'est son identité, pas un réglage par défaut. Les exports ci-dessus
alimentent les couches de mise en application que vous exécutez déjà (fail2ban, nginx, un WAF de périphérie). Mais certains déploiements
n'ont aucune couche de ce type à alimenter — hébergement mutualisé, PaaS, conteneurs derrière un équilibreur de charge que vous
ne contrôlez pas. Pour ceux-là, le paquet expose ses *décisions* sous forme de helpers, et vous écrivez
vous-même le middleware de mise en application. Même architecture que les exports : **nous fournissons
l'intelligence, vous fournissez le refus.**```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);
    }
}

Avant d’appliquer une règle basée sur l’IP, configurez TrustProxies.

Tout ce qui précède dépend de $request->ip(). Derrière un équilibreur de charge, un CDN ou proxy inverse, cet appel ne renvoie l’IP du client que lorsque Laravel sait à quels proxies faire confiance. Si ce n’est pas le cas, deux problèmes surviennent à la fois : chaque requête semble provenir du proxy, donc une entrée de liste de blocage bloque tout votre trafic ou rien du tout — et pire, si l’application fait confiance à un en-tête transféré qu’elle ne devrait pas approuver, un attaquant définit X-Forwarded-For et traverse directement la liste de blocage.

C’est encore plus important ici que pour whitelisted_ips. Une erreur de correspondance de liste blanche signifie seulement que le package analyse une requête qu’il aurait pu ignorer : il échoue en mode sûr. Une liste de blocage utilisée pour refuser du trafic échoue en mode ouvert — vous croyez qu’une adresse est bloquée alors qu’elle ne l’est pas. Vérifiez app/Http/Middleware/TrustProxies.php (ou l’appel trustProxies dans bootstrap/app.php sous Laravel 11+) avant de vous appuyer sur l’un ou l’autre helper pour l’application des règles.

Enregistrez-le globalement (avant le middleware de détection, c’est sans problème — les helpers lisent la configuration et le cache, ils ne dépendent pas de l’ordre des middlewares) :```php // bootstrap/app.php (Laravel 11+) ->withMiddleware(function ($middleware) { $middleware->prepend(\App\Http\Middleware\EnforceThreatDecisions::class); })

The helpers:

| Helper | Retourne | Basé sur |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | config `blocklisted_ips` (CIDR via `IpUtils` ; la liste blanche gagne) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | config `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | le compteur de flood que maintient le middleware de détection |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | ce compteur vs `ddos.threshold` |

Notes:

- **La denylist est statique et maintenue par l'opérateur.** Rien dans le package ne vient jamais l'enrichir — il exécute la même décision qu'une prison fail2ban (« J'ai lu le tableau de bord ; ce /24 est hostile »), juste dans l'application.
- Le compteur DDoS ne compte que les requêtes ayant atteint la détection (`skip_paths`, les adresses IP en liste blanche et les environnements désactivés ne sont jamais comptés), et reste à 0 sur les pilotes de cache où la détection DDoS est désactivée (`file`, `database`, `null`).
- Lorsqu'un client dépasse le seuil, un événement [`DdosThresholdExceeded`](#ddosthresholdexceeded-event) est également déclenché — utile pour alerter ou alimenter une liste de bannissement externe. N'appelez toutefois pas `abort()` depuis le listener : les listeners s'exécutent dans le `try/catch` fail-open du middleware de détection, le refus relève donc de votre propre middleware comme ci-dessus.

---

## Suivi des sondes 404

Le package détecte les sondes de reconnaissance -  des bots qui frappent des chemins vulnérables connus comme `/wp-admin`, `/.env`, ou `/phpmyadmin` sur votre site non-WordPress, non-phpMyAdmin. Elles ne contiennent aucune charge utile malveillante ; le chemin lui-même est le signal.

Journalisées avec une étiquette de type `[probe]`, distinctes de la détection basée sur la charge utile. Si une requête de sonde contient également une charge utile malveillante, les deux sont journalisées indépendamment.

Activé par défaut avec plus de 50 chemins de sondes. Personnalisez dans `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...
    ],
],

Désactiver avec THREAT_DETECTION_PROBE_TRACKING=false.


Champs sûrs (Réduction des faux positifs)

Si des champs de formulaire spécifiques contiennent légitimement du HTML, des mots-clés SQL ou du code (par exemple, les éditeurs CMS, les champs de saisie d'extraits de code), vous pouvez les exclure de l'analyse :```php // config/threat-detection.php 'safe_fields' => ['content', 'body', 'html', 'description', 'code'],

Les champs listés ici sont retirés des paramètres de requête et du corps de la requête -  à la fois codés en formulaire et JSON (`application/json`) - avant que la détection ne s'exécute. Les autres champs de la même requête sont toujours entièrement analysés.

### Chemins sûrs (conscients du chemin, pour les API JSON imbriquées)

`safe_fields` correspond à un nom de clé **n'importe où** il apparaît. Pour les API JSON imbriquées, c'est souvent trop large — vous pouvez souhaiter exempter la valeur d'un champ spécifique sans exempter cette clé partout. Utilisez `safe_paths`, qui correspond par **chemin** en notation par points et prend en charge les wildcards `fnmatch` :```php
// config/threat-detection.php
'safe_paths' => ['search.query', 'filters.*.value'],

Par exemple, search.query exempte la valeur de {"search": {"query": "..."}} (une boîte de recherche dont le texte contient légitimement des mots comme SELECT), tandis qu'un champ query ailleurs dans la requête est toujours analysé. Tout ce qui n'est pas listé est analysé exactement comme avant.

Validateurs post-correspondance (réduction des faux positifs par somme de contrôle)

Une regex seule ne peut pas exprimer toutes les contraintes : toute suite de 12 chiffres correspond au motif Aadhaar, mais un vrai numéro Aadhaar passe également la somme de contrôle de Verhoeff. Associez une étiquette de motif (par défaut ou personnalisée) à un validateur nommé, et une correspondance regex ne compte comme détection que si au moins une valeur correspondante le valide :```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],

Validateurs disponibles:

| Validateur  | Somme de contrôle | Usage typique |
|------------|----------|-------------|
| `verhoeff` | Verhoeff | numéros Aadhaar |
| `luhn`     | Luhn     | numéros de cartes de crédit/débit |

Avec le mappage fourni, les horodatages, les identifiants de commande et les codes-barres ayant 12 chiffres ne sont plus journalisés comme données personnelles — alors que les véritables numéros Aadhaar le sont toujours. Si plusieurs valeurs correspondent et qu'une seule passe la somme de contrôle, la détection se déclenche quand même : un numéro réel parmi le bruit reste une fuite.

Associez un validateur à votre propre motif pour la détection de cartes basée sur la somme de contrôle:```php
'custom_patterns'    => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],

Un nom de validateur inconnu échoue en mode ouvert — la correspondance est comptée comme non validée et un avertissement est journalisé une fois — de sorte qu'une faute de frappe ne peut jamais désactiver silencieusement un motif de détection. Les configurations publiées avant cette fonctionnalité ne possèdent tout simplement pas la clé et conservent exactement leur comportement actuel.


Expurgation (Détecter n'est pas stocker)

Détecter des données sensibles signifiait autrefois les stocker. Un formulaire de profil contenant un numéro de mobile, un PAN et un compte bancaire déclencherait trois motifs de PII, et chacune des trois lignes écrites conservait l'intégralité du corps de la requête tel quel - conservée pendant toute la période de rétention, lisible par quiconque ayant accès au tableau de bord ou à la base de données. Une valeur dans une chaîne de requête atterrissait également dans la colonne url. Le détecteur devenait une seconde copie concentrée de ce dont il vous avertit exactement.

Activé par défaut depuis la v1.7.0. Lorsqu'un motif dont le libellé est listé se déclenche, la valeur correspondante est masquée dans la charge utile stockée et l'URL :``` BODY: {"name":"Jane Doe","mobile":"[REDACTED]","pan":"[REDACTED]","bank_account":"[REDACTED]"}

L'alerte, l'endpoint, les noms des champs et l'IP attaquante survivent tous - seule la valeur disparaît. Le masquage s'exécute *après* la détection, donc rien n'est manqué.```php
// config/threat-detection.php
'redact' => [
    'enabled' => env('THREAT_DETECTION_REDACT', true),
    'mask'    => '[REDACTED]',
    'labels'  => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],

Les payloads d'attaque sont délibérément laissés intacts - une chaîne d'injection est une preuve, pas un secret, et la masquer détruirait l'investigation. Seules les étiquettes que vous listez sont touchées.

Cela ne remplace pas Safe Fields. Ceux-ci empêchent un champ d'être analysé; le masquage vous permet de continuer à analyser et d'arrêter le stockage. Définissez THREAT_DETECTION_REDACT=false si vous avez besoin des payloads complets pour la forensique.


Tableau de bord et authentification de l'API

Le tableau de bord et l'API prennent en charge des gardes d'authentification configurables via .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

Les mêmes options sont disponibles pour les routes API avec `THREAT_DETECTION_API_GUARD`.

Lorsque `guard=none` (par défaut), le package enregistre un avertissement une fois par jour pour vous rappeler de configurer l'authentification.

Le guard **échoue en position fermée** : une valeur de guard non reconnue (par ex. une faute de frappe) est refusée avec une erreur 403 et un avertissement journalisé, plutôt que d'accorder silencieusement l'accès, et `guard=role` refuse (avec un avertissement) lorsque le modèle d'utilisateur authentifié ne possède pas de méthode `hasRole()`.

### Désactiver une détection nécessite plus qu'un accès en lecture

Marquer une menace comme faux positif et supprimer une règle d'exclusion désactivent tous deux un type de détection pour tout le monde, ce qui est un privilège différent de celui de lire le journal. Ces deux endpoints sont vérifiés par un guard distinct :```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role

Il s'applique uniquement à ces routes, donc la lecture et le tableau de bord se comportent exactement comme le dit THREAT_DETECTION_API_GUARD. Sans cela, tout utilisateur authentifié de votre application pourrait désactiver une détection.

Si votre modèle utilisateur n'a pas de hasRole(), utilisez =auth. Pour restaurer le comportement d'avant la 1.7.0 où tout utilisateur authentifié pouvait désactiver des détections, utilisez =none - threat-detection:doctor émettra un avertissement tant que cela est défini.

Remarque Dashboard ↔ API : le tableau de bord intégré récupère ses données depuis les routes API en utilisant le cookie de session du navigateur. Si vos routes API sont protégées par auth:sanctum, configurez l'authentification Sanctum stateful/SPA (ou orientez le tableau de bord vers un garde authentifié par cookie) afin que ces appels AJAX soient autorisés - sinon le tableau de bord se vide.


Modèles personnalisés

Ajoutez vos propres expressions régulières de détection dans config/threat-detection.php :```php 'custom_patterns' => [ '/your-regex-here/i' => 'Your Threat Label', ],

**Exemple -  détecter une sonde d'endpoint admin personnalisée :**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',

Forme tableau (options par motif)

En plus de la forme chaîne classique, la valeur d'un motif peut être un tableau pour un contrôle complet :```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`** définit directement le niveau de menace au lieu de le dériver des mots-clés `threat_levels` du libellé.
- **`contexts`** limite l'analyse à des segments de requête spécifiques — par exemple, un motif de carte qui n'a de sens que dans le corps cesse de correspondre aux suites de chiffres dans les en-têtes.
- **`validator`** nomme une vérification post-correspondance en ligne (voir [Validateurs post-correspondance](#post-match-validators-checksum-aware-false-positive-reduction)) ; il prime sur la table `pattern_validators` du libellé.

Les entrées de chaînes et de tableaux se mélangent librement dans la même configuration. Les options mal formées **échouent en mode ouvert** — le motif continue d'analyser, sans restriction, et un avertissement est journalisé — de sorte qu'une erreur de configuration ne peut jamais désactiver ni restreindre silencieusement une détection.

> **Remarque :** Les chemins de sonde courants comme `/wp-login.php`, `/.env`, `/phpmyadmin` sont désormais gérés automatiquement par la fonctionnalité [404 Probe Tracking](#404-probe-tracking). Vous n'avez pas besoin de motifs personnalisés pour ceux-ci.

Le niveau de menace de chaque motif est déterminé automatiquement en confrontant les mots-clés du libellé à la configuration `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 l'étiquette ne correspond à aucun mot-clé, la menace utilise par défaut la sévérité low.

Les motifs regex invalides sont automatiquement ignorés et journalisés comme avertissements - ils ne feront pas planter votre application.


Utilisation de la façade

Pour un accès programmatique aux données de menace en dehors du 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');

---

## Passage en production

Le paquet est passif par conception : il ne bloque, ne rejette ni ne modifie jamais une requête, et le middleware de détection enveloppe l'intégralité de son corps dans `try/catch`, de sorte qu'un échec de détection ne peut jamais casser votre application. Il est livré avec des valeurs par défaut raisonnables et ne nécessite aucun service externe pour fonctionner. Avant de passer en production, cette petite liste de contrôle mérite un coup d'œil :

1. **Protégez le tableau de bord et l'API.** Les deux utilisent par défaut `guard = none` pour un premier lancement sans configuration, et enregistrent un avertissement quotidien tant qu'ils ne sont pas protégés. Avant la production, définissez un garde - `THREAT_DETECTION_DASHBOARD_GUARD` et `THREAT_DETECTION_API_GUARD` (`auth`, `role` ou `ip`). Une valeur non reconnue ou un garde `role` sur un modèle utilisateur sans `hasRole()` **échoue en mode fermé** (403), de sorte qu'une faute de frappe ne peut pas exposer silencieusement les données. La désactivation d'une détection est contrôlée séparément par `THREAT_DETECTION_API_WRITE_GUARD`, qui est défini par défaut sur `role`. Voir [Authentification du tableau de bord et de l'API](#dashboard-and-api-authentication).
2. **Exécutez les migrations** (`vendor:publish --tag=threat-detection-migrations && migrate`). La republication est sûre - les migrations déjà publiées sont ignorées.
3. **Choisissez un mode de détection.** `balanced` (par défaut) convient à la plupart des applications ; utilisez `relaxed` pour les sites à forte teneur en contenu, `strict` pour les surfaces à haute sécurité. Ajustez avec `content_paths`, `safe_fields` et `min_confidence` - voir [Réduction des faux positifs](#reducing-false-positives).
4. **Révisez les motifs régionaux de PII / motifs personnalisés.** Les valeurs par défaut sont centrées sur l'Inde (Aadhaar, PAN, IFSC) et les motifs numériques larges (par ex. compte bancaire) peuvent correspondre à de longs identifiants numériques en dehors des routes d'authentification. Remplacez ou réduisez `custom_patterns` selon votre région et votre application, et ajoutez les routes à contenu dense à `auth_paths` / `content_paths`.
5. **Activez la rétention** si vous attendez du volume : `THREAT_DETECTION_RETENTION=true` (purge automatique via le planificateur). Nécessite que le planificateur de Laravel (`schedule:run`) soit piloté par cron.
6. **Extras optionnels, tous désactivés par défaut :** alertes Slack (`THREAT_DETECTION_NOTIFICATIONS`), géo-enrichissement (`php artisan threat-detection:enrich` - la seule fonctionnalité qui effectue un appel sortant, vers le service gratuit ip-api.com), et écritures en file d'attente (`THREAT_DETECTION_QUEUE` - à activer uniquement si vous exécutez déjà un worker de file d'attente ; sinon les écritures sont synchrones et ne nécessitent pas Redis).

Aucun Redis, aucun worker de file d'attente et aucun appel réseau sortant ne sont requis pour la détection et la journalisation de base.

---

## Réduction des faux positifs

Le paquet fournit plusieurs outils pour réduire les faux positifs. Utilisez celui qui correspond à votre situation :

### Champs sûrs et chemins sûrs

Excluez entièrement un champ de l'analyse, soit par nom partout (`safe_fields`), soit par chemin en notation pointée pour le JSON imbriqué (`safe_paths`). L'approche la plus simple, et la plus radicale - le champ est ignoré, donc aucune détection ne s'y exécute.

Tous les détails et exemples : [Champs sûrs](#safe-fields-false-positive-reduction).

### Suppression par chemin de contenu

Si vous avez des éditeurs CMS, des formulaires d'articles de blog ou des sections de commentaires où les utilisateurs soumettent du contenu riche, ces chemins déclenchent souvent des faux positifs (par ex., un article de blog contenant des extraits de code `<script>`). Ajoutez ces chemins pour supprimer les alertes faibles/moyennes :```php
// config/threat-detection.php
'content_paths' => [
    'admin/posts/*',
    'admin/pages/*',
    'blog/*/edit',
    'comments',
],

Sur ces chemins, seules les menaces à haute sévérité sont journalisées.

Signalement des faux positifs

Cliquez sur le bouton FP de n'importe quelle menace dans le tableau de bord pour la marquer comme faux positif. Cela :

  1. Marque la menace comme is_false_positive = true
  2. Crée automatiquement une règle d'exclusion afin que les menaces similaires provenant de la même URL/type soient supprimées à l'avenir

Gérez les règles d'exclusion via l'API :```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}

### Score de confiance

Chaque menace reçoit un score de confiance (0-100) basé sur :
- Nombre de correspondances de motifs dans la même requête
- Gravité du motif correspondant
- Où le motif a été trouvé (chaîne de requête > en-têtes > corps)
- Si le user-agent correspond à un outil d'attaque connu
- Mode de détection actuel

Les menaces en dessous du seuil de confiance pour votre mode de détection ne sont pas journalisées (voir [Modes de détection](#detection-modes)).

---

## Types d'attaques détectés

| Catégorie | Exemples |
|----------|---------|
| **Injection SQL** | UNION, booléen, basé sur le temps, encodage CHAR, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), opérations de fichiers (INTO OUTFILE, LOAD_FILE), énumération ORDER BY, chaînes hexadécimales, UNHEX |
| **Injection NoSQL** | opérateurs MongoDB $ne, $gt, $regex, $where |
| **XSS** | balises script, gestionnaires d'événements SVG (`<svg onload=`), gestionnaires d'événements HTML (`<body onload=`, `<img onerror=`), expressions CSS, URI JavaScript, manipulation DOM |
| **Exécution de code** | fonctions shell RCE, désérialisation PHP, désérialisation Java (base64 + octets magiques hexadécimaux), injection de modèles (Blade, JSP, ASP, Jinja2, Velocity), eval(), décodage base64, assert() PHP, create_function(), preg_replace /e |
| **SSTI** | sondes mathématiques (`{{7*7}}`), import/config Jinja2, modèles Velocity, Expression Language |
| **Injection de commandes** | Linux (fonctions shell, chaînes de commandes, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Accès aux fichiers** | traversée de répertoire, protocoles LFI/RFI, sondes de fichiers sensibles (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), métadonnées AWS/GCP, adresses IP privées, localhost encodé en hexadécimal/décimal, rebinding DNS (xip.io, nip.io, sslip.io) |
| **Injection LDAP** | manipulation de filtres LDAP, injection OR |
| **Injection XPath** | sélecteurs d'attributs, fonctions XPath (contains, substring) |
| **Injection CRLF / en-têtes** | CRLF encodé en URL (`%0d%0a`), injection LF, injection d'octet nul |
| **Attaques de protocole** | contrebande de requêtes HTTP (CL+TE), injection SSI |
| **Exploits CVE** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Suivi des sondes** | WordPress (`/wp-admin`, `/wp-login.php`), fichiers de configuration (`/.env`, `/.git`), outils de base de données (`/phpmyadmin`), sondes de technologie (`.asp`, `.jsp`), Spring actuator, documentation Swagger/API -  50+ chemins |
| **Scanners** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei, et 20+ autres (53 au total) |
| **Scrapers IA** | GPTBot, ClaudeBot, ChatGPT, ByteSpider, Cohere, Common Crawl |
| **Navigateurs headless** | HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright |
| **Bots** | scripts Python, clients HTTP Go, cURL, wget, AhrefsBot, SEMRushBot, user agents vides |
| **Authentification** | détection de force brute, fuites de jetons, exposition de mots de passe, exposition d'ID de session |
| **DDoS** | détection de requêtes excessives basée sur le débit |
| **Évasion** | insertion de commentaires SQL, double encodage URL, encodage d'entités HTML, échappements Unicode, Unicode IIS, échappements hexadécimaux |
| **Autre** | introspection GraphQL, pollution de prototypes, redirection ouverte, XXE, web shells, minage de crypto, détection de PII |

---

## Exécution de la suite de tests```bash
composer test

Le paquet inclut 335 tests (856 assertions) couvrant les modèles de détection, le comportement du middleware, les points de terminaison de l'API, le score de confiance, les règles d'exclusion, la détection DDoS, la résistance à l'évasion, les modèles CVE, l'injection LDAP/XPath/SSTI, la détection de bots/scanners, le suivi des sondes, les commandes d'exportation, l'authentification du tableau de bord, les champs sûrs, les optimisations des performances et la vérification complète du cycle HTTP vers base de données.


Licence

Licence MIT. Voir LICENSE pour plus de détails.

Contribution

Les contributions sont les bienvenues ! Veuillez soumettre une Pull Request.

Crédits

Catégories