Retour aux mises à jour
New releaseSep 3, 2026

laravel-threat-detection v1.7.2

Middleware Laravel passif qui détecte et journalise les injections SQL, les XSS, les RCE, les scanners de bots et plus de 175 modèles d'attaques. Doté d'un tableau de bord intégré, d'alertes Slack, d'une API REST et d'un enrichissement géographique. IDS, pas WAF.

Partager

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

Laravel Threat Detection

Surveillance de sécurité et journalisation des attaques pour Laravel. Détectez et journalisez les injections SQL, XSS, RCE, traversées de répertoire, scanners de bots et sondes de reconnaissance de type /wp-admin — chaque requête hostile enregistrée dans votre base de données avec le contexte applicatif complet. C'est un IDS, pas un WAF : il ne bloque, ne filtre et ne modifie jamais une requête.

Install the package, send three attacks — SQL injection, directory traversal, XSS — every one returns HTTP 200 because nothing is blocked, and all three are already counted in threat-detection:stats

Êtes-vous ici parce que vous avez vu quelque chose comme ceci ?```

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

Ces requêtes atteignent déjà votre application Laravel. Votre journal d'accès affiche l'URL
et le code de statut, et rien d'autre — ni la charge utile décodée, ni laquelle de vos
routes a été ciblée, ni si la même IP a essayé quarante autres choses cette heure-ci.

Ce package répond à ces questions. Déposez-le dans n'importe quelle application Laravel 10–13 et il commence
à analyser chaque requête HTTP par rapport à plus de 150 motifs d'attaque, en évaluant chaque correspondance par
confiance 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/liste de blocage. Aucune requête n'est jamais bloquée. Pensez
caméra de surveillance, pas verrou : 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. 1 857 tests, aucune dépendance
> d'exécution en dehors de Laravel lui-même, et aucune connexion internet requise pour la détection.
>
> Vous mettez à jour ? Voir [UPGRADING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/UPGRADING.md). Vous contribuez ? Voir [CONTRIBUTING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/CONTRIBUTING.md).

## Démarrage en moins d'une minute```bash
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Ensuite, ajoutez 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 Quick Start ci-dessous. C'est tout ; la détection est active.```bash php artisan threat-detection:doctor # confirms it is actually recording

---

## Où cela s'intègre : IDS vs WAF vs edge

Ce package est un **IDS passif au niveau applicatif** — 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 peuvent pas voir :

| | **Ce package** (IDS applicatif) | **WAF** (mod_security, Cloudflare WAF) | **Edge / CDN** (Cloudflare) |
|---|:---:|:---:|:---:|
| Bloque les requêtes malveillantes | ❌ journalise uniquement | ✅ | ✅ |
| Contexte applicatif complet (route exacte, payload décodé, 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 (ex. Aadhaar / PAN / IFSC PII) | ✅ motifs personnalisés | ❌ | ❌ |
| Fonctionne hors ligne / sans service externe | ✅ | ⚠️ selon le cas | ❌ |
| Stoppe le trafic avant qu'il n'atteigne votre application | ❌ | ✅ edge | ✅ |
| Installation | un `composer require` | moyenne–élevée | faible–moyenne |
| Coût | gratuit, MIT | variable | offre gratuite + payant |

**En résumé :** un edge/WAF est votre serrure sur la porte ; ceci est la caméra de surveillance
*à 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,
géo-blocage — 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 et 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 déléguer ? Les
  [helpers côté opérateur](#acting-on-the-data-operator-side-blocking) exposent les
  décisions du package pour 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 package.)
- **Pas un remplacement pour le codage 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 package suppose que votre code est déjà
  sécurisé et vous donne de la *visibilité*, pas de la protection.
- **Pas un service edge.** Si vous pouvez placer Cloudflare devant, faites-le — puis ajoutez ceci pour le
  niveau de détail applicatif que les services edge ne peuvent pas voir.
- **Pas un détecteur complet, et il ne peut pas l'être.** La correspondance de motifs attrape les attaques qui
  *ressemblent à* des attaques connues. Une technique nouvelle, ou une technique familière suffisamment réécrite,
  passera sans être journalisée — et vous ne serez pas informé qu'elle l'a fait. Le silence ici signifie
  « rien n'a correspondu », jamais « rien ne s'est produit ». Là où il gagne sa place, c'est sur le
  trafic à fort volume et à faible effort qui constitue la majeure partie de ce qui frappe réellement une application
  Laravel publique : scanners, sondes de reconnaissance, chaînes d'injection toutes faites, pulvérisations
  d'identifiants. Traitez un journal silencieux comme une absence de preuve, pas comme une preuve d'absence.

### Attendez-vous à ce qu'il signale votre propre contenu dès le premier jour

Une installation non réglée se déclenche sur du contenu légitime, et vous devriez le savoir avant
d'installer plutôt qu'après. Ces cas sont mesurés, pas hypothétiques — la suite épingle cette liste exacte pour qu'elle ne puisse pas dériver ([`LegitimateTrafficCorpusTest`](https://github.com/jay123anta/laravel-threat-detection/blob/main/tests/Feature/LegitimateTrafficCorpusTest.php)) :

<!-- noise-floor:start -->
| Requête parfaitement légitime | Ce qu'une installation non réglée journalise |
|---|---|
| `how to write a UNION SELECT in postgres` saisi dans un champ de recherche | `SQL Injection UNION` / high |
| Un article de blog contenant `<script>window.dataLayer=[];</script>` | `XSS Script Tag` / high |
| Un ticket de support avec un message d'erreur `SELECT * FROM users WHERE id = 1` collé | `SQLi Variant` / high |
| Une documentation expliquant que `../../etc/passwd` est le payload de traversée classique | `Directory Traversal` / medium |
| Un formulaire de profil collectant un véritable numéro de mobile indien et un PAN | `PAN Number Detected` / high |
<!-- noise-floor:end -->

**Aucun de ces cas n'est un bug.** Un article de blog contenant `<script>` est, octet pour octet, un
payload de XSS stocké ; une recherche de `UNION SELECT` est indiscernable d'une tentative
d'en faire une. Rien d'autre que le contexte applicatif ne les sépare, et aucun moteur de motifs ne peut
fournir ce contexte à votre place.

Le fournir est un changement de configuration d'une ligne — `safe_fields`, `safe_paths`,
`content_paths`, ou le mode `relaxed`. Voir [Réduire les faux positifs](#reducing-false-positives).
**Si votre application accepte du texte enrichi, des exemples de code, ou des requêtes de recherche, faites-le avant de
juger la sortie.** La valeur par défaut est délibérément bruyante-mais-honnête plutôt que
silencieuse-et-incomplète : il est plus facile de faire taire une correspondance connue que de découvrir une correspondance qui
ne s'est jamais déclenchée.

### Alors qu'en faites-vous concrètement ?

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

| Vous voulez | Utilisez | Effort |
|---|---|---|
| Voir ce qui vous frappe | Le [tableau de bord](#dashboard) ou `threat-detection:stats` | aucun, c'est déjà en cours d'exécution |
| Bannir les récidivistes au niveau du pare-feu | [`threat-detection:export-fail2ban`](#artisan-commands) — pipez vers un cron | une ligne |
| Refuser au niveau du serveur web | [`threat-detection:export-blocklist`](#artisan-commands) → directives nginx/apache | une ligne |
| Refuser les requêtes dans l'application | [Helpers côté opérateur](#acting-on-the-data-operator-side-blocking) — `isBlocklisted()`, `isDdosThresholdExceeded()` | ~10 lignes de votre propre middleware |
| Réagir en temps réel | L'[événement `ThreatDetected`](#threatdetected-event) — Telegram, SIEM, PagerDuty | un listener |

Le package fournit le renseignement ; 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 du 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.


### Comment il se compare aux autres packages de sécurité Laravel

Ceux-ci résolvent des problèmes différents et se composent bien — le tableau vise à choisir le
bon outil, pas à gagner.

| Package | Ce qu'il fait | Bloque ? | Utilisez-le quand |
|---|---|:---:|---|
| **ce package** | Analyse chaque requête contre plus de 150 motifs, journalise avec le contexte applicatif complet | ❌ | Vous voulez *voir* ce qui est tenté sur votre application |
| `spatie/laravel-honeypot` | Champ de formulaire caché qui attrape les bots de spam | ✅ formulaire uniquement | Vous avez des formulaires publics spammés |
| `graham-campbell/security` | Supprime le balisage de type XSS des entrées | ✅ modifie | Vous voulez un assainissement naïf des entrées |
| `spatie/laravel-csp` | Envoie des en-têtes Content-Security-Policy | ✅ navigateur | Vous voulez contraindre ce que le navigateur charge |
| `laravel/fortify` + limites de débit | Limitation et verrouillage de l'authentification | ✅ | Vous avez besoin d'une protection contre la force brute à la connexion |
| Cloudflare / mod_security | WAF edge, bloque avant votre application | ✅ | Vous voulez que le trafic soit stoppé avant d'arriver |

Le résumé honnête : un honeypot attrape le spam de formulaire, un WAF bloque le trafic connu comme malveillant
au niveau edge, et CSP contraint le navigateur. **Aucun d'entre eux ne vous dit ce qu'un
attaquant a tenté contre vos routes spécifiques, avec le payload décodé et l'utilisateur
authentifié attaché.** C'est ce vide que ce package comble — et c'est pourquoi le
package ne bloque délibérément pas : vous pouvez l'exécuter aux côtés de tout ce qui précède
sans qu'aucun d'entre eux ne se combatte.

---

## 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)
- N'importe quel driver de cache -  **aucun Redis ni worker de queue requis**. Redis/Memcached est
  seulement *recommandé* pour activer la vérification DDoS optionnelle (qui se désactive automatiquement sur
  les drivers non atomiques). Les écritures en queue sont opt-in et désactivées par défaut.

---

## Comment ça fonctionne

1. Un middleware analyse chaque requête HTTP entrante
2. La requête est vérifiée contre 158 motifs regex couvrant l'injection SQL, le XSS, le RCE, la traversée de fichiers, le SSRF, le LDAP, le XPath, le SSTI, et plus encore
3. Si un motif de menace correspond, un enregistrement est écrit dans votre table de base de données `threat_logs` avec l'IP, l'URL, le type de menace, le niveau de gravité, et un score de confiance
4. Optionnellement, une alerte Slack est envoyée pour les menaces de gravité élevée
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 package```bash
composer require jayanta/laravel-threat-detection

2. Publier les migrations et les exécuter

Cette étape est obligatoire. Sans elle, le package détectera les menaces mais ne pourra pas les stocker dans la base de données. Si vous sautez cette étape, votre table threat_logs n'existera pas et toutes les détections seront silencieusement perdues (vous ne verrez les erreurs que 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érifier que les tables ont été créées :**```bash
php artisan migrate:status

Cherchez create_threat_logs_table, add_confidence_to_threat_logs_table et create_threat_exclusion_rules_table - tous devraient 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 sensées. Publier la configuration vous permet de personnaliser les motifs de détection, les modes de sensibilité, les notifications Slack, et plus encore. Si vous sautez cette étape, tout fonctionne toujours.

**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é enregistrée.

### Étape 1 : Démarrer 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=<script>alert(1)</script>

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 un 404, le middleware n'a peut-être pas été exécuté.

### Étape 3 : Vérifier que les menaces ont été journalisées

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

Vous devriez voir un tableau avec Recorded Detections, les décomptes de sévérité et les principales IP. Ce nombre compte des lignes, pas des tentatives : une détection est écrite une fois par IP par type de menace par tranche de cinq minutes, et les répétitions à l'intérieur de cette fenêtre sont dédupliquées plutôt que comptées à nouveau.

Option B - Tinker :```bash php artisan tinker

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

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

### Points à connaître lors des tests

| Comportement | Explication |
|----------|-------------|
| Une même menace n'est journalisée qu'une fois toutes les 5 minutes | Déduplication : même IP + même type de menace est mis en cache pendant 5 minutes. Utilisez **différents types d'attaques** 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 » (sévérité faible). C'est attendu - le package détecte les outils automatisés. |
| Le package ne bloque jamais les requêtes | Votre application continue de fonctionner normalement. La détection est passive. |
| Aucune configuration Slack nécessaire | Les notifications sont désactivées par défaut. |
| Aucune connexion internet nécessaire | La détection principale est 100 % locale. Seule la commande optionnelle `threat-detection:enrich` appelle une API externe pour les géo-données. |

### Dépannage

**Commencez ici — une seule commande répond à la plupart de ces points :**```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 à « aucune attaque » — et affiche la correction exacte pour chacun. Il se termine avec un code non nul en cas d'échec réel, il est donc sûr de l'exécuter dans une 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 élimine **toutes** les menaces) ; les colonnes dashboard/API ; la
table des règles d'exclusion ; si le middleware est réellement relié à une route ou à un
groupe ; une configuration publiée antérieure à cette version ; des patterns personnalisés qui masquent
ceux intégrés ; un driver de cache incapable d'assurer le comptage DDoS ; et un dashboard 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 est passé, 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 à votre place :

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

> Exécuter `php artisan migrate` seul ne suffit jamais : les fichiers de migration se trouvent
> à l'intérieur du package et doivent d'abord être publiés dans le `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 dashboard affiche 404 »**

Le dashboard 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

  • Plus de 150 motifs 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 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 ciblant 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 par seuil de débit avec fenêtres configurables
  • Score de confiance - Chaque menace reçoit un score de confiance de 0 à 100 basé sur le nombre de motifs, 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 des motifs
  • Détection de CVE - Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
  • Détection contextuelle - Les motifs trouvés dans les chaînes de requête obtiennent un score plus élevé que ceux trouvés dans le corps de la requête
  • Analyse du corps de la requête - Les corps de requête encodés en formulaire et JSON (application/json) sont inspectés
  • Champs sûrs - Exclure des champs de formulaire spécifiques de l'analyse (pour les éditeurs CMS, les entrées de code, les champs de recherche)
  • Signalement des faux positifs - Marquer les 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é ajustable
  • Suppression des chemins de contenu - Mettre en liste blanche les chemins CMS/blog pour supprimer les alertes de niveau faible/moyen provenant de contenu riche
  • Détection de données personnelles (PII) - Motifs d'exposition de données sensibles (configurable par région)
  • Enrichissement géographique - Identification du pays, de la ville, du FAI, du fournisseur cloud via une API gratuite
  • Alertes Slack - Notifications en temps réel pour les menaces de haute gravité (fonctionne sur Laravel 10 et 11+)
  • Tableau de bord intégré - Tableau de bord Blade en mode sombre (Alpine.js + Tailwind CDN, aucune étape de build)
  • Protection d'authentification du tableau de bord - Authentification configurable pour le tableau de bord et l'API (aucune, auth, rôle ou basée sur l'IP)
  • 15 points de terminaison 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 dans un format compatible fail2ban ou une liste de blocage simple
  • Export de liste de blocage - Exporter les IP au format nginx deny, Apache deny, CSV ou brut
  • Export CSV - Export du journal des 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
  • Optimisation des performances - Chargement paresseux des motifs par catégorie (n'exécute les regex que pour les catégories d'attaque pertinentes), sortie anticipée pour les requêtes propres, court-circuit pour les UA de navigateur (ignore 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 valeurs par défaut sensées
  • 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 du fichier .env. Toutes les valeurs ci-dessous sont optionnelles - 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

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).

HTTPS since v1.8.0. A failed lookup is never retried over cleartext, and a

run in which every lookup failed exits non-zero rather than reporting

success. Enrichment is opt-in either way.

ip-api.com's free tier rejects HTTPS, so on the free tier this command will

now fail rather than quietly sending your visitors' IP addresses in the

clear. Either point it at a provider you hold a key for, or set it back

explicitly and accept the disclosure.

THREAT_DETECTION_GEO_ENDPOINT=https://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

### Modes de détection

| Mode | Seuil de confiance | Comportement |
|------|---------------------|----------|
| `strict` | 0 (journalise tout) | Tous les motifs actifs, seuils les plus bas. Détecte tout mais peut signaler du trafic légitime. |
| `balanced` | 10 | Par défaut. Notation de confiance active, seuils standards. Adapté à la plupart des applications. |
| `relaxed` | 40 | Seuls les motifs de haute sévérité se déclenchent. Idéal pour les sites riches en contenu avec de fréquents faux positifs. |

### Environnements activés

Par défaut, la détection s'exécute en `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 de configuration clés : skip_paths (chemins à ignorer), only_paths (mode liste blanche), auth_paths (détection intelligente pour les routes de connexion), content_paths (suppression des alertes non élevées), safe_fields (exclure des champs spécifiques de l'analyse), safe_paths (exclusion de champs sensible au chemin pour JSON imbriqué), probe_tracking (détection de sonde 404), context_weights (multiplicateurs de score), threat_levels (mappage des mots-clés de gravité), api_route_filtering (suppression des niveaux faible/moyen sur les routes API), queue (traitement asynchrone), retention (purge automatique), max_detections_per_request (plafond 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 - aucune surcharge de middleware.```php // config/threat-detection.php 'only_paths' => [ 'admin/', 'api/', 'login', 'register', ],

Laisser vide (par défaut) pour analyser 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 au sein de l'ensemble correspondant.

### Prise en charge des files d'attente

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

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

Auto-Purge (politique de rétention)

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

Nécessite que le planificateur de Laravel soit en cours d'exécution (`php artisan schedule:run`). S'exécute quotidiennement à 02:00 via `threat-detection:purge`.

### Événement ThreatDetected

Chaque 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 la 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 franchit le seuil DDoS configuré (ddos.threshold requêtes dans ddos.window secondes), un événement DdosThresholdExceeded est dispatché en parallèle de l'entrée du journal de 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 limitation que la ligne de log), afin qu'un flood ne puisse pas
noyer vos listeners. Utilisez-le pour l'alerte ou pour alimenter un store de bannissement externe ; pour *refuser*
les clients dépassant le seuil, utilisez `ThreatDetection::isDdosThresholdExceeded($ip)` depuis votre propre
middleware à la place — voir [Acting on the Data](#acting-on-the-data-operator-side-blocking).

---

## Slack Notifications

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 haute gravité déclenchent des notifications par défaut (configurable via notify_levels dans la configuration).

Laravel 10 : Utilise la classe de notification SlackMessage intégrée. 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 vers 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

<p align="center">
  <img src="https://assets.kitploit.com/production/public/readmes/12500/fc7950bd0cc6323bcc2d62b03e31c99edc7450b0ef76f9cbfa5133b527b25269.png" alt="Tableau de bord de détection des menaces — statistiques, chronologie sur 7 jours, journal des menaces en direct, principales IP fautives et menaces par pays" width="100%">
</p>

Le paquet est livré avec un tableau de bord intégré en mode sombre (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 au tableau de bord en développement local

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

Toutes les options de garde, ainsi que la garde distincte sur les endpoints qui désactivent les détections, sont couvertes dans Dashboard and API Authentication.

Si le tableau de bord affiche des données vides, la page s'est chargée mais ses appels API n'ont pas abouti. Voir API Authentication.


API Endpoints

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

API Authentication

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

  • Sanctum installé : L'API nécessite une authentification via des tokens Sanctum ou l'authentification de session SPA.
  • Sanctum NON installé : Le package détecte automatiquement que Sanctum est absent 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 - Utiliser la garde d'authentification intégrée :```env THREAT_DETECTION_API_GUARD=auth

**Option 2 - Modifier directement le middleware :**```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'

> Restaurez l'authentification avant de déployer en production.

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

| Méthode | Point de terminaison | Description |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Lister les menaces (paginé, filtrable) |
| GET | `/api/threat-detection/threats/{id}` | Détails d'une menace |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Marquer une menace comme faux positif |
| GET | `/api/threat-detection/stats` | Statistiques globales |
| GET | `/api/threat-detection/summary` | Répartition 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` | Regroupées par pays |
| GET | `/api/threat-detection/by-cloud-provider` | Regroupées par fournisseur cloud |
| GET | `/api/threat-detection/top-ips` | Principales IP fautives |
| GET | `/api/threat-detection/timeline` | Chronologie des menaces (pour les 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` | Lister les 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` | Rechercher 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 (par 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éation d'interfaces personnalisées

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 Sanctum SPA 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)

Defaults to https://ip-api.com/json, rate-limited to 45 req/min and

auto-throttled. The free tier rejects HTTPS - see THREAT_DETECTION_GEO_ENDPOINT.

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 comportement par défaut. Les exports ci-dessus
alimentent les couches d'application que vous exécutez déjà (fail2ban, nginx, un WAF en périphérie). Mais certains déploiements
n'ont aucune de ces couches à 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 d'assistants, et vous écrivez vous-même le
middleware d'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 des règles sur l'IP, configurez TrustProxies.

Tout ce qui précède repose sur $request->ip(). Derrière un load balancer, un CDN ou un reverse proxy, cela ne renvoie l'IP du client que lorsque Laravel est informé des proxys à faire confiance. Si ce n'est pas le cas, deux choses se cassent en même temps : chaque requête semble provenir du proxy, donc une entrée de denylist bloque tout votre trafic ou aucun — et pire, si l'application fait confiance à un en-tête transféré auquel elle ne devrait pas, un attaquant définit X-Forwarded-For et traverse directement la blocklist.

Cela importe davantage ici que pour whitelisted_ips. Une correspondance erronée dans la whitelist signifie seulement que le package analyse une requête qu'il aurait pu ignorer : il échoue en sécurité. Une denylist utilisée pour refuser le trafic échoue en ouverture — 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 sur Laravel 11+) avant de vous fier à l'un ou l'autre helper pour l'application des règles.

Enregistrez-le globalement (avant le middleware de détection, c'est très bien — les helpers lisent la config 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); })

Les helpers :

| Helper | Retourne | Basé sur |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | configuration `blocklisted_ips` (CIDR via `IpUtils` ; la whitelist est prioritaire) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | configuration `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | le compteur de flood maintenu par le middleware de détection |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | ce compteur comparé à `ddos.threshold` |

Notes :

- **La denylist est statique et maintenue par l'opérateur.** Rien dans le package ne l'alimente
  jamais — il exécute la même décision qu'une jail fail2ban prendrait (« J'ai lu le dashboard ; ce /24
  est hostile »), mais au sein de l'application.
- Le compteur DDoS ne compte que les requêtes ayant atteint la détection (`skip_paths`, IP
  whitelistées et environnements désactivés ne sont jamais comptés), et reste à 0 sur les drivers de cache
  où la détection DDoS est désactivée (`file`, `database`, `null`).
- Lorsqu'un client franchit le seuil, un [événement `DdosThresholdExceeded`](#ddosthresholdexceeded-event)
  est également dispatché — utile pour l'alerting ou pour alimenter une liste de bannissement externe. N'appelez pas `abort()`
  depuis le listener, cependant : les listeners s'exécutent à l'intérieur du `try/catch` fail-open du middleware de détection,
  donc le refus appartient à 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 et non-phpMyAdmin. Celles-ci n'ont aucune charge utile malveillante ; le chemin lui-même est le signal.

Journalisées avec un tag de type `[probe]`, distinct 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. Personnalisable 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, des éditeurs CMS, des 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 encodé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 (sensibles au chemin, pour les API JSON imbriquées)

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

Par exemple, search.query exempte la valeur de {"search": {"query": "..."}} (une zone de recherche dont le texte contient légitimement des mots comme SELECT), tandis qu'un champ query situé 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 sensible aux sommes de contrôle)

Une expression régulière seule ne peut pas exprimer toutes les contraintes : toute suite de 12 chiffres correspond au motif Aadhaar, mais un véritable 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 d'expression régulière n'est comptée comme une détection que lorsqu'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 | Utilisation typique |
|------------|-------------------|---------------------|
| `verhoeff` | Verhoeff | Numéros Aadhaar |
| `luhn`     | Luhn     | Numéros de carte de crédit/débit |

Avec le mapping fourni, les horodatages, les identifiants de commande et les codes-barres qui font par hasard 12 chiffres ne sont plus journalisés comme PII — tandis 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 vrai numéro parmi le bruit reste une fuite.

Associez un validateur à votre propre motif pour une détection de carte contrôlée par 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 — ainsi une faute de frappe ne peut jamais désactiver silencieusement un motif de détection. Les configurations publiées avant cette fonctionnalité n'ont tout simplement pas la clé et conservent leur comportement actuel exact.


Redaction (Détecter n'est pas stocker)

Détecter des données sensibles signifiait auparavant les stocker. Un formulaire de profil contenant un numéro de mobile, un PAN et un compte bancaire déclencherait trois motifs PII, et chacune des trois lignes écrites conservait le corps de la requête entier mot pour mot - conservé 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 aussi dans la colonne url. Le détecteur devenait une seconde copie concentrée de exactement ce dont il vous avertit.

Activé par défaut depuis la v1.7.0. Lorsqu'un motif dont le libellé est listé se déclenche, la valeur qu'il a correspondée 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, le point de terminaison, les noms de champs et l'IP attaquante survivent tous - seule la valeur disparaît. La rédaction 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 charges utiles d'attaque sont délibérément laissées intactes - une chaîne d'injection est une preuve, pas un secret, et la masquer détruirait l'investigation. Seuls les libellés que vous listez sont touchés.

Cela ne remplace pas les Champs sûrs. Ceux-ci empêchent un champ d'être analysé ; la rédaction vous permet de continuer l'analyse et d'arrêter le stockage. Définissez THREAT_DETECTION_REDACT=false si vous avez besoin des charges utiles complètes pour la forensique.


Authentification du tableau de bord et 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 mode fermé** : une valeur de guard non reconnue (par exemple une faute de frappe) est refusée avec un 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é n'a 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 constitue un privilège différent de la lecture du journal. Ces deux endpoints sont vérifiés par rapport à un guard distinct :```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role

Cela 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 antérieur à la 1.7.0 où tout utilisateur authentifié pouvait désactiver les détections, utilisez =none - threat-detection:doctor émettra un avertissement tant que cela est défini.

Note Tableau de bord ↔ 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 avec auth:sanctum, configurez l'authentification Sanctum stateful/SPA (ou pointez le tableau de bord vers un guard authentifié par cookie) afin que ces appels AJAX soient autorisés - sinon le tableau de bord s'affiche vide.


Custom Patterns

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

**Exemple - détecter une sonde de point de terminaison d'administration 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 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`** définit directement le niveau de menace au lieu de le dériver des mots-clés `threat_levels` dans le label.
- **`contexts`** restreint l'analyse à des segments de requête spécifiques — par exemple, un motif de carte qui n'a de sens que dans le body cesse de correspondre à des suites de chiffres dans les en-têtes.
- **`validator`** nomme une vérification post-correspondance inline (voir [Post-Match Validators](#post-match-validators-checksum-aware-false-positive-reduction)) ; elle a la priorité sur la map de labels `pattern_validators`.

Les entrées de type chaîne et tableau se mélangent librement dans la même configuration. Les options malformées **échouent en mode ouvert** — le motif est toujours analysé, sans restriction, et un avertissement est journalisé — ainsi une erreur de configuration ne peut jamais désactiver ou 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 pour chaque motif est déterminé automatiquement en faisant correspondre les mots-clés du label avec 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 le libellé ne correspond à aucun mot-clé, la menace est par défaut de sévérité low.

Les motifs regex invalides sont automatiquement ignorés et consignés sous forme d'avertissements - ils ne feront pas planter votre application.


Utilisation de la Facade

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 package est passif par conception - il ne bloque, ne rejette et ne modifie jamais une requête, et le middleware de détection enveloppe tout son corps dans un `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 sensées et ne nécessite aucun service externe pour fonctionner. Avant de passer en production, cette courte checklist vaut le coup d'œil :

1. **Protégez le tableau de bord et l'API.** Les deux sont par défaut sur `guard = none` pour une première exécution sans configuration, et journalisent un avertissement quotidien tant qu'ils ne sont pas protégés. Avant la production, définissez un guard - `THREAT_DETECTION_DASHBOARD_GUARD` et `THREAT_DETECTION_API_GUARD` (`auth`, `role`, ou `ip`). Une valeur non reconnue ou un guard `role` sur un modèle utilisateur sans `hasRole()` **échoue désormais en mode fermé** (403), donc une faute de frappe n'exposera pas 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 vaut `role` par défaut. 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`). Une nouvelle publication est sans danger - 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 riches 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. **Passez en revue les PII régionales / 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 ajustez `custom_patterns` pour votre région et votre application, et ajoutez les routes à contenu lourd à `auth_paths` / `content_paths`.
5. **Activez la rétention** si vous prévoyez du volume : `THREAT_DETECTION_RETENTION=true` (purge automatique via le scheduler). Nécessite que le scheduler de Laravel (`schedule:run`) soit piloté par cron.
6. **Extras optionnels, tous désactivés par défaut :** alertes Slack (`THREAT_DETECTION_NOTIFICATIONS`), enrichissement géographique (`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 package fournit plusieurs outils pour réduire les faux positifs. Utilisez celui qui correspond à votre situation :

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

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

Détails complets 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 exemples de code `<script>`). Ajoutez ces chemins pour supprimer les alertes de niveau faible/moyen :```php
// config/threat-detection.php
'content_paths' => [
    'admin/posts/*',
    'admin/pages/*',
    'blog/*/edit',
    'comments',
],

Sur ces chemins, seules les menaces de gravité élevée sont journalisées.

Signalement de faux positifs

Cliquez sur le bouton FP sur 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/du même 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}

### Attribution de score de confiance

Chaque menace reçoit un score de confiance (0-100) basé sur :
- Le nombre de correspondances de motifs dans la même requête
- La gravité du motif correspondant
- L'endroit 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
- Le 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ées

| Catégorie | Exemples |
|----------|---------|
| **Injection SQL** | UNION, booléenne, temporelle, encodage CHAR, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), opérations sur 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 du DOM |
| **Exécution de code** | Fonctions shell RCE, désérialisation PHP, désérialisation Java (base64 + octets magiques hex), injection de template (Blade, JSP, ASP, Jinja2, Velocity), eval(), décodage base64, PHP assert(), create_function(), preg_replace /e |
| **SSTI** | Sondes mathématiques (`{{7*7}}`), import/config Jinja2, templates Velocity, Expression Language |
| **Injection de commande** | 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, IP privées, localhost encodé en hex/décimal, DNS rebinding (xip.io, nip.io, sslip.io) |
| **Injection LDAP** | Manipulation de filtre LDAP, injection OR |
| **Injection XPath** | Sélecteurs d'attributs, fonctions XPath (contains, substring) |
| **Injection CRLF / d'en-tête** | CRLF encodé 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 de sondes** | WordPress (`/wp-admin`, `/wp-login.php`), fichiers de configuration (`/.env`, `/.git`), outils de base de données (`/phpmyadmin`), sondes technologiques (`.asp`, `.jsp`), Spring actuator, Swagger/API docs - 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 sans interface** | 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, IIS Unicode, échappements hex |
| **Autre** | Introspection GraphQL, pollution de prototype, redirection ouverte, XXE, web shells, minage de cryptomonnaie, détection de PII |

---

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

Le package inclut 1 857 tests (4 950 assertions) couvrant les motifs de détection, le comportement du middleware, les points de terminaison API, le scoring de confiance, les règles d'exclusion, la détection DDoS, la résistance à l'évasion, les motifs CVE, l'injection LDAP/XPath/SSTI, la détection de bots/scanners, le suivi des sondes, les commandes d'export, l'authentification du tableau de bord, les champs sécurisés, les optimisations de performance et la vérification complète du cycle HTTP-vers-BD.


License

MIT License. See LICENSE for details.

Contributing

Contributions are welcome! Please submit a Pull Request.

Credits

Catégories