Torna agli aggiornamenti
New releaseSep 3, 2026

laravel-threat-detection v1.7.2

Middleware Laravel passivo che rileva e registra SQL injection, XSS, RCE, scanner bot e oltre 175 pattern di attacco. Include una dashboard integrata, avvisi Slack, API REST e arricchimento geografico. IDS, non WAF.

Condividi

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

Laravel Threat Detection

Monitoraggio della sicurezza e registrazione degli attacchi per Laravel. Rileva e registra SQL injection, XSS, RCE, directory traversal, bot scanner e sonde di ricognizione in stile /wp-admin — ogni richiesta ostile viene registrata nel tuo database con il contesto completo dell'applicazione. È un IDS, non un WAF: non blocca, filtra o modifica mai una richiesta.

Installa il pacchetto, invia tre attacchi — SQL injection, directory traversal, XSS — ognuno restituisce HTTP 200 perché nulla viene bloccato, e tutti e tre sono già conteggiati in threat-detection:stats

Sei qui perché hai visto qualcosa del genere?```

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

Quelle richieste stanno già raggiungendo la tua app Laravel. Il tuo access log mostra l'URL
e il codice di stato, e nient'altro — non il payload decodificato, non quale delle tue
route è stata presa di mira, non se lo stesso IP ha provato quaranta altre cose in questa ora.

Questo pacchetto risponde a queste domande. Inseriscilo in qualsiasi app Laravel 10–13 e inizia
a scansionare ogni richiesta HTTP rispetto a oltre 150 pattern di attacco, assegnando un punteggio a ogni corrispondenza in base
alla confidenza e scrivendolo nel tuo database — con una dashboard integrata, avvisi Slack,
geo-arricchimento ed esportazioni fail2ban/blocklist. Nessuna richiesta viene mai bloccata. Pensa a
una telecamera di sicurezza, non a una serratura: ti mostra esattamente chi sta sondando le tue route, quanto
spesso e con quali tecniche.

> Estratto da un'app di produzione e collaudato su traffico reale. 1.857 test, nessuna dipendenza
> runtime oltre a Laravel stesso, e nessuna connessione internet richiesta per il rilevamento.
>
> Stai aggiornando? Vedi [UPGRADING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/UPGRADING.md). Vuoi contribuire? Vedi [CONTRIBUTING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/CONTRIBUTING.md).

## Inizia in meno di un minuto```bash
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Poi aggiungi il middleware al tuo gruppo web (una riga in bootstrap/app.php su Laravel 11+, o app/Http/Kernel.php su Laravel 10) — lo snippet completo è in Quick Start qui sotto. Tutto qui; il rilevamento è attivo.```bash php artisan threat-detection:doctor # confirms it is actually recording

---

## Dove si colloca: IDS vs WAF vs edge

Questo pacchetto è un **IDS passivo a livello applicativo** — osserva e registra, non
blocca. È pensato per affiancare un WAF o un servizio edge, non per sostituirli. Ogni livello vede
qualcosa che gli altri non possono vedere:

| | **Questo pacchetto** (app IDS) | **WAF** (mod_security, Cloudflare WAF) | **Edge / CDN** (Cloudflare) |
|---|:---:|:---:|:---:|
| Blocca richieste malevole | ❌ solo log | ✅ | ✅ |
| Contesto completo dell'app (route esatta, payload decodificato, utente autenticato) | ✅ | ⚠️ parziale | ❌ |
| Dashboard integrata + log delle minacce nel tuo DB | ✅ | ⚠️ variabile | ⚠️ solo edge |
| Rilevamenti specifici dell'app (es. PII Aadhaar / PAN / IFSC) | ✅ pattern personalizzati | ❌ | ❌ |
| Funziona offline / nessun servizio esterno | ✅ | ⚠️ dipende | ❌ |
| Ferma il traffico prima che raggiunga la tua app | ❌ | ✅ edge | ✅ |
| Setup | un `composer require` | medio–alto | basso–medio |
| Costo | gratuito, MIT | variabile | tier gratuito + a pagamento |

**In breve:** un edge/WAF è la serratura sulla porta; questo è la telecamera di sicurezza
*all'interno*, con il contesto dell'app per dirti esattamente cosa viene tentato su quale route, da
chi, e con quale frequenza. Usalo per alimentare decisioni reali — ban fail2ban, rate limit,
geo-blocking — con dati che il tuo livello edge non vede mai.

### Cosa deliberatamente NON è

- **Non è un WAF.** Non blocca, filtra o modifica mai una richiesta. Usa Cloudflare,
  mod_security, o un vero WAF per l'enforcement. (Nessun livello edge a cui delegare? Gli
  [helper lato operatore](#acting-on-the-data-operator-side-blocking) espongono le
  decisioni del pacchetto così puoi scrivere il tuo middleware di blocco in cinque righe —
  il codice di enforcement resta tuo, non del pacchetto.)
- **Non è un sostituto della programmazione sicura.** Query parametrizzate, validazione dell'input, e
  escaping dell'output sono le tue difese reali. Questo pacchetto presuppone che il tuo codice sia già
  sicuro e ti offre *visibilità*, non protezione.
- **Non è un servizio edge.** Se puoi mettere Cloudflare davanti, fallo — poi aggiungi questo per il
  dettaglio a livello applicativo che i servizi edge non possono vedere.
- **Non è un rilevatore completo, e non può esserlo.** Il pattern matching intercetta attacchi che
  *sembrano* attacchi noti. Una tecnica nuova, o una familiare riscritta a sufficienza, passerà
  senza essere registrata — e non ti verrà detto che è successo. Il silenzio qui significa
  "niente ha corrisposto", mai "niente è successo". Dove si guadagna il suo posto è nel
  traffico ad alto volume e basso sforzo che costituisce la maggior parte di ciò che effettivamente colpisce un'app
  Laravel pubblica: scanner, sonde di ricognizione, stringhe di injection pronte all'uso, credential
  spray. Tratta un log silenzioso come assenza di prove, non come prova di assenza.

### Aspettati che segnali i tuoi stessi contenuti dal primo giorno

Un'installazione non tarata scatta su contenuti legittimi, e dovresti saperlo prima
di installare piuttosto che dopo. Questi sono misurati, non ipotetici — la suite
fissa questa esatta lista così non può variare ([`LegitimateTrafficCorpusTest`](https://github.com/jay123anta/laravel-threat-detection/blob/main/tests/Feature/LegitimateTrafficCorpusTest.php)):

<!-- noise-floor:start -->
| Richiesta perfettamente legittima | Cosa registra un'installazione non tarata |
|---|---|
| `how to write a UNION SELECT in postgres` digitato in un campo di ricerca | `SQL Injection UNION` / high |
| Un post del blog contenente `<script>window.dataLayer=[];</script>` | `XSS Script Tag` / high |
| Un ticket di supporto con un errore `SELECT * FROM users WHERE id = 1` incollato | `SQLi Variant` / high |
| Documentazione che spiega che `../../etc/passwd` è il classico payload di traversal | `Directory Traversal` / medium |
| Un form di profilo che raccoglie un numero di cellulare indiano autentico e un PAN | `PAN Number Detected` / high |
<!-- noise-floor:end -->

**Nessuno di questi è un bug.** Un post del blog contenente `<script>` è, byte per byte, un
payload di XSS memorizzato; una ricerca di `UNION SELECT` è indistinguibile da un tentativo
di farlo. Nient'altro che il contesto dell'applicazione li separa, e nessun motore di pattern può
fornirti quel contesto.

Fornirlo è una modifica di configurazione di una riga — `safe_fields`, `safe_paths`,
`content_paths`, o modalità `relaxed`. Vedi [Ridurre i falsi positivi](#reducing-false-positives).
**Se la tua app accetta rich text, esempi di codice, o query di ricerca, fallo prima di
giudicare l'output.** Il default è deliberatamente rumoroso-ma-onesto piuttosto che
silenzioso-e-incompleto: è più facile silenziare una corrispondenza nota che scoprirne una che
non è mai scattata.

### Quindi cosa ci fai effettivamente?

La domanda più comune su un rilevatore che non blocca mai. Quattro risposte, in
ordine crescente di sforzo:

| Vuoi | Usa | Sforzo |
|---|---|---|
| Vedere cosa ti sta colpendo | La [dashboard](#dashboard) o `threat-detection:stats` | nessuno, è già in esecuzione |
| Bannare i recidivi al firewall | [`threat-detection:export-fail2ban`](#artisan-commands) — pipe a un cron | una riga |
| Negare al web server | [`threat-detection:export-blocklist`](#artisan-commands) → direttive nginx/apache | una riga |
| Rifiutare le richieste in-app | [Helper lato operatore](#acting-on-the-data-operator-side-blocking) — `isBlocklisted()`, `isDdosThresholdExceeded()` | ~10 righe del tuo middleware |
| Reagire in tempo reale | L'[evento `ThreatDetected`](#threatdetected-event) — Telegram, SIEM, PagerDuty | un listener |

Il pacchetto fornisce l'intelligence; tu fornisci il rifiuto. Questa separazione è
deliberata — il codice di enforcement che vive nella tua app è codice che puoi leggere,
testare e disattivare, e significa che un bug di rilevamento non può mai mandare giù il tuo sito.


### Come si confronta con altri pacchetti di sicurezza Laravel

Questi risolvono problemi diversi e si compongono bene — la tabella riguarda la scelta dello
strumento giusto, non la vittoria.

| Pacchetto | Cosa fa | Blocca? | Usalo quando |
|---|---|:---:|---|
| **questo pacchetto** | Scansiona ogni richiesta contro 150+ pattern, registra con il contesto completo dell'app | ❌ | Vuoi *vedere* cosa viene tentato sulla tua app |
| `spatie/laravel-honeypot` | Campo form nascosto che intercetta bot di spam | ✅ solo form | Hai form pubblici che ricevono spam |
| `graham-campbell/security` | Rimuove markup simil-XSS dall'input | ✅ muta | Vuoi un sanitizing ingenuo dell'input |
| `spatie/laravel-csp` | Invia header Content-Security-Policy | ✅ browser | Vuoi limitare cosa carica il browser |
| `laravel/fortify` + rate limit | Throttling e lockout dell'autenticazione | ✅ | Ti serve protezione brute-force sul login |
| Cloudflare / mod_security | WAF edge, blocca prima della tua app | ✅ | Vuoi fermare il traffico prima che arrivi |

Il riassunto onesto: un honeypot intercetta lo spam dei form, un WAF blocca il traffico noto-malevolo
all'edge, e CSP limita il browser. **Nessuno di loro ti dice cosa un
attaccante ha tentato contro le tue route specifiche, con il payload decodificato e l'utente
autenticato allegato.** Quel divario è ciò che questo colma — ed è per questo che il
pacchetto deliberatamente non blocca: puoi eseguirlo insieme a tutti i suddetti
senza che nessuno di loro si combatta a vicenda.

---

## Requisiti

- PHP 8.2+ (Laravel 13 richiede PHP 8.3+)
- Laravel 10.x, 11.x, 12.x, o 13.x
- Qualsiasi database supportato da Laravel (MySQL, PostgreSQL, SQLite, SQL Server)
- Qualsiasi driver di cache -  **nessun Redis o queue worker richiesto**. Redis/Memcached è
  solo *raccomandato* per abilitare il controllo DDoS opzionale (che si disabilita automaticamente su
  driver non atomici). Le scritture in coda sono opt-in e disattivate di default.

---

## Come Funziona

1. Un middleware scansiona ogni richiesta HTTP in ingresso
2. La richiesta viene verificata contro 158 pattern regex che coprono SQL injection, XSS, RCE, file traversal, SSRF, LDAP, XPath, SSTI, e altro
3. Se un pattern di minaccia corrisponde, un record viene scritto nella tua tabella `threat_logs` del database con IP, URL, tipo di minaccia, livello di severità, e un punteggio di confidenza
4. Opzionalmente, un avviso Slack viene inviato per minacce ad alta severità
5. La richiesta procede normalmente -  **niente viene bloccato**

Nessuna connessione internet è necessaria per il rilevamento.

---

## Avvio Rapido

### 1. Installa il pacchetto```bash
composer require jayanta/laravel-threat-detection

2. Pubblicare le migrazioni ed eseguirle

Questo passaggio è obbligatorio. Senza di esso, il pacchetto rileverà le minacce ma non potrà memorizzarle nel database. Se salti questo passaggio, la tua tabella threat_logs non esisterà e tutte le rilevazioni andranno perse silenziosamente (vedrai solo gli errori in storage/logs/laravel.log).```bash php artisan vendor:publish --tag=threat-detection-migrations php artisan migrate

Questo crea due tabelle: `threat_logs` (memorizza le minacce rilevate) e `threat_exclusion_rules` (memorizza le regole per i falsi positivi).

**Verifica che le tabelle siano state create:**```bash
php artisan migrate:status

Cerca create_threat_logs_table, add_confidence_to_threat_logs_table e create_threat_exclusion_rules_table - tutti dovrebbero mostrare Ran.

3. Registra il middleware

Il middleware è ciò che analizza le richieste. Devi aggiungerlo al tuo gruppo di middleware web.

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

> **Come controllare la tua versione di Laravel:** Esegui `php artisan --version` nel tuo terminale.

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

4. (Opzionale) Pubblicare il file di configurazione```bash

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

Il pacchetto funziona con impostazioni predefinite sensate. Pubblicando la configurazione puoi personalizzare i pattern di rilevamento, le modalità di sensibilità, le notifiche Slack e altro ancora. Se salti questo passaggio, tutto continua a funzionare.

**Fatto.** La tua app ora rileva le minacce.

---

## Verifica che funzioni

Dopo l'installazione, attiva una minaccia di test e conferma che sia stata registrata.

### Passaggio 1: Avvia la tua app```bash
php artisan serve

Passaggio 2: Apri un URL di test nel tuo browser

Aggiungi un parametro di query malevolo a qualsiasi route esistente nella tua app (la tua homepage, una pagina prodotto, ecc.). Ad esempio:

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

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

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

**RCE (Remote Code Execution):**```
http://localhost:8000/?cmd=system('ls -la')

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

**Iniezione di comandi Windows:**```
http://localhost:8000/?cmd=powershell -c whoami

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

> Usa una route che esiste effettivamente nella tua app (come `/`). Se l'URL restituisce un 404, il middleware potrebbe non essere stato eseguito.

### Passaggio 3: Verifica che le minacce siano state registrate

**Opzione A - Comando Artisan (il più rapido):**```bash
php artisan threat-detection:stats

Dovresti vedere una tabella con Recorded Detections, i conteggi di gravità e gli IP principali. Quel numero conta le righe, non i tentativi: una detection viene scritta una volta per IP per tipo di minaccia ogni cinque minuti, e le ripetizioni all'interno di quella finestra vengono deduplicate anziché conteggiate di nuovo.

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

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

Opzione C - File di log di Laravel: Ogni minaccia rilevata viene scritta come avviso in storage/logs/laravel.log:``` [high] Threat Detected: [middleware] SQL Injection UNION from 127.0.0.1 (http://localhost:8000/?q=...) [confidence: 50%]

### Cose da sapere durante i test

| Comportamento | Spiegazione |
|----------|-------------|
| La stessa minaccia viene registrata una sola volta ogni 5 minuti | Deduplicazione: lo stesso IP + lo stesso tipo di minaccia viene memorizzato nella cache per 5 minuti. Usa **tipi di attacco diversi** per ogni test, oppure attendi tra un test e l'altro. |
| Le richieste `curl` attivano un rilevamento aggiuntivo | L'uso di `curl` registra anche un rilevamento dello user-agent "cURL Command" (gravità bassa). Questo è previsto - il pacchetto rileva gli strumenti automatizzati. |
| Il pacchetto non blocca mai le richieste | La tua app continua a funzionare normalmente. Il rilevamento è passivo. |
| Nessuna configurazione di Slack necessaria | Le notifiche sono disattivate per impostazione predefinita. |
| Nessuna connessione a Internet necessaria | Il rilevamento principale è 100% locale. Solo il comando opzionale `threat-detection:enrich` chiama un'API esterna per i geo-dati. |

### Risoluzione dei problemi

**Inizia da qui — un solo comando risponde alla maggior parte di questi:**```bash
php artisan threat-detection:doctor

Controlla le cose che fanno fallire il rilevamento silenziosamente — dove la dashboard rimane vuota, il che sembra identico a "nessun attacco" — e stampa la correzione esatta per ciascuna. Esce con codice diverso da zero in caso di un vero fallimento, quindi è sicuro da eseguire in CI o in una fase di deploy.``` 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.

Cosa copre: rilevamento abilitato per questo ambiente; ogni colonna di cui lo
scrittore ha bisogno (una mancante scarta **ogni** minaccia); colonne dashboard/API; la
tabella delle regole di esclusione; se il middleware è effettivamente collegato a una route o
a un gruppo; configurazione pubblicata precedente a questa versione; pattern personalizzati che oscurano
quelli integrati; un driver di cache che non può eseguire il conteggio DDoS; e una dashboard o
API lasciata aperta senza autenticazione.

**"Ho testato ma `threat-detection:stats` mostra zero minacce" / "Le minacce non vengono memorizzate nel database"**

Se il doctor è passato, l'installazione è a posto e il problema è la richiesta di test
stessa. Tre cose che non può verificare per te:

| Verifica | Come verificare |
|-------|---------------|
| L'IP non è in whitelist | Se hai aggiunto `THREAT_DETECTION_WHITELISTED_IPS` a `.env`, rimuovilo durante il test |
| Hai usato una route esistente | L'URL di test deve corrispondere a una route reale (es. `/`). Un 404 significa che il middleware non è mai stato eseguito |
| Cache di deduplicazione | Stesso IP + stesso tipo di attacco è in cache per 5 minuti - prova un tipo di attacco diverso |

> Eseguire solo `php artisan migrate` non è mai sufficiente: i file di migrazione si trovano
> all'interno del pacchetto e devono prima essere pubblicati in `database/migrations/`
> della tua app. Il doctor stampa il comando esatto quando questo è il problema.

**"L'API restituisce 401 Unauthorized"**

Vedi [Autenticazione API](#api-authentication) di seguito.

**"La dashboard mostra 404"**

La dashboard è disabilitata per impostazione predefinita. Aggiungi `THREAT_DETECTION_DASHBOARD=true` a `.env` e svuota la cache delle route:```bash
php artisan route:clear

Funzionalità

  • Oltre 150 pattern di rilevamento - SQL injection (UNION, DDL, DML, operazioni su file), XSS (script, SVG, espressione CSS), RCE, directory traversal, SSRF, XXE, Log4Shell, NoSQL injection, command injection (Linux + Windows), LDAP injection, XPath injection, SSTI, CRLF injection, deserializzazione Java e altro ancora
  • 83 firme di bot/scanner - SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker e oltre 70 altre firme di scanner e bot
  • Rilevamento scraper AI - GPTBot, ClaudeBot, ByteSpider, Common Crawl e altri bot di addestramento AI
  • Rilevamento browser headless - HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright
  • Tracciamento sonde 404 - Rileva sonde di ricognizione che colpiscono percorsi vulnerabili noti (/wp-admin, /.env, /phpmyadmin, /actuator, ecc.) con oltre 50 percorsi di sonda predefiniti
  • Monitoraggio DDoS - Rilevamento basato su soglia di frequenza con finestre configurabili
  • Punteggio di confidenza - Ogni minaccia riceve un punteggio di confidenza da 0 a 100 basato sul numero di pattern, contesto e segnali
  • Resistenza all'evasione - La pipeline di normalizzazione neutralizza l'inserimento di commenti SQL, la doppia codifica URL, la codifica di entità HTML, gli escape Unicode e gli escape esadecimali prima del pattern matching
  • Rilevamento CVE - Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
  • Rilevamento context-aware - I pattern trovati nelle query string ottengono un punteggio più alto rispetto a quelli nel corpo della richiesta
  • Scansione del corpo della richiesta - Vengono ispezionati sia i corpi delle richieste form-encoded che JSON (application/json)
  • Campi sicuri - Escludi campi modulo specifici dalla scansione (per editor CMS, input di codice, campi di ricerca)
  • Segnalazione falsi positivi - Contrassegna le minacce come falsi positivi dalla dashboard; crea automaticamente regole di esclusione
  • Tre modalità di rilevamento - strict, balanced (predefinita) e relaxed - sensibilità regolabile
  • Soppressione percorsi di contenuto - Inserisci in whitelist i percorsi CMS/blog per sopprimere gli avvisi di bassa/media gravità da contenuti ricchi
  • Rilevamento PII - Pattern di esposizione di dati sensibili (configurabili per regione)
  • Geo-arricchimento - Identificazione di paese, città, ISP, provider cloud tramite API gratuita
  • Avvisi Slack - Notifiche in tempo reale per minacce ad alta gravità (funziona su Laravel 10 e 11+)
  • Dashboard integrata - Dashboard Blade in dark mode (Alpine.js + Tailwind CDN, zero build step)
  • Protezione autenticazione dashboard - Autenticazione configurabile per dashboard e API (nessuna, auth, ruolo o basata su IP)
  • 15 endpoint API - API REST completa per costruire dashboard personalizzate Vue/React/mobile
  • Esportazione Fail2ban - Esporta gli IP rilevati in formato compatibile con fail2ban o come blocklist semplice
  • Esportazione blocklist - Esporta gli IP in formato nginx deny, Apache deny, CSV o semplice
  • Esportazione CSV - Esportazione del log delle minacce con un clic (fino a 10.000 righe)
  • Analisi di correlazione - Rileva attacchi coordinati e campagne di attacco tra IP
  • Prestazioni ottimizzate - Caricamento lazy dei pattern basato su categorie (esegue regex solo per le categorie di attacco rilevanti), uscita anticipata per richieste pulite, short-circuit UA browser (salta oltre 70 controlli per browser normali), lookup hash dei percorsi di sonda, inserimenti DB in batch, numero massimo di rilevamenti configurabile per richiesta
  • Indipendente dal database - MySQL, PostgreSQL, SQLite, SQL Server
  • Zero configurazione - Funziona subito con valori predefiniti sensati
  • Sicuro per progettazione - Il middleware intercetta i propri errori. Se il rilevamento fallisce, la tua app continua a funzionare. Le richieste non vengono mai bloccate.

Configurazione

Il pacchetto funziona senza alcuna modifica al file .env. Tutti i valori seguenti sono opzionali - aggiungili solo se vuoi sovrascrivere i valori predefiniti.```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

### Modalità di Rilevamento

| Modalità | Soglia di Confidenza | Comportamento |
|------|---------------------|----------|
| `strict` | 0 (registra tutto) | Tutti i pattern attivi, soglie più basse. Cattura tutto ma potrebbe segnalare traffico legittimo. |
| `balanced` | 10 | Predefinita. Punteggio di confidenza attivo, soglie standard. Adatta alla maggior parte delle app. |
| `relaxed` | 40 | Si attivano solo i pattern ad alta severità. Ideale per siti con molto contenuto e frequenti falsi positivi. |

### Ambienti Abilitati

Per impostazione predefinita, il rilevamento viene eseguito in `production`, `staging` e `local`. Per modificare, pubblica la configurazione e modifica:```php
'enabled_environments' => ['production', 'staging', 'local'],

Per disabilitare il rilevamento nella tua suite di test, imposta APP_ENV=testing (non presente nell'elenco sopra) oppure aggiungi al tuo phpunit.xml:```xml

### Riferimento alla configurazione

Pubblica il file di configurazione per vedere tutte le opzioni disponibili:```bash
php artisan vendor:publish --tag=threat-detection-config

Sezioni chiave della configurazione: skip_paths (percorsi da saltare), only_paths (modalità whitelist), auth_paths (rilevamento intelligente per le route di login), content_paths (sopprime gli avvisi non-high), safe_fields (esclude campi specifici dalla scansione), safe_paths (esclusione dei campi basata sul percorso per JSON annidati), probe_tracking (rilevamento delle sonde 404), context_weights (moltiplicatori di punteggio), threat_levels (mappatura delle parole chiave di gravità), api_route_filtering (sopprime low/medium sulle route API), queue (elaborazione asincrona), retention (eliminazione automatica), max_detections_per_request (limite per le prestazioni), dashboard.guard / api.guard (modalità di autenticazione).

Whitelisting delle route (only_paths)

Se la tua applicazione ha molte route ma te ne interessano solo alcune, usa only_paths per scansionare solo quelle route. Tutte le altre route vengono automaticamente saltate - nessun overhead del middleware.```php // config/threat-detection.php 'only_paths' => [ 'admin/', 'api/', 'login', 'register', ],

Lasciare vuoto (predefinito) per scansionare tutte le route (soggetto a `skip_paths`). Quando entrambi sono configurati, `only_paths` viene verificato per primo, poi `skip_paths` si applica all'interno dell'insieme corrispondente.

### Supporto alle code

Per impostazione predefinita, la registrazione delle minacce avviene in modo sincrono nel ciclo di richiesta. Per applicazioni ad alto traffico, è possibile scaricare le scritture su DB e le notifiche Slack su una coda:```env
THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=threat-logs

Questo invia un job StoreThreatLog (3 tentativi, backoff 10s/30s). Il rilevamento avviene comunque in tempo reale - solo la scrittura è differita.

Auto-Purge (Retention Policy)

Elimina automaticamente i vecchi threat log con una pianificazione giornaliera:```env THREAT_DETECTION_RETENTION=true THREAT_DETECTION_RETENTION_DAYS=90

Richiede che lo scheduler di Laravel sia in esecuzione (`php artisan schedule:run`). Viene eseguito quotidianamente alle 02:00 tramite `threat-detection:purge`.

### Evento ThreatDetected

Ogni minaccia confermata invia un evento `ThreatDetected` che puoi ascoltare:```php
// app/Providers/EventServiceProvider.php
use JayAnta\ThreatDetection\Events\ThreatDetected;

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

L'evento trasporta $threatLog (array completo della riga del DB), $ipAddress e $threatLevel. Usalo per attivare azioni personalizzate - inviare avvisi Telegram, aggiornare una blocklist, alimentare un SIEM, ecc.

Evento DdosThresholdExceeded

Quando un client supera la soglia DDoS configurata (ddos.threshold richieste entro ddos.window secondi), viene inviato un evento DdosThresholdExceeded insieme alla voce del registro delle minacce:```php use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;

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

L'evento trasporta `$ipAddress`, `$requestCount`, `$threshold` e `$windowSeconds`. È
limitato a una volta per IP per finestra di deduplicazione (stesso throttle della riga di log), quindi un flood non può
sovraccaricare i tuoi listener. Usalo per l'alerting o per alimentare un archivio di ban esterno; per *rifiutare*
i client oltre la soglia, usa `ThreatDetection::isDdosThresholdExceeded($ip)` dal tuo
middleware — vedi [Acting on the Data](#acting-on-the-data-operator-side-blocking).

---

## Notifiche Slack

Gli avvisi Slack sono disabilitati per impostazione predefinita. Per abilitarli:```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Solo le minacce ad alta gravità attivano le notifiche per impostazione predefinita (configurabile tramite notify_levels nella configurazione).

Laravel 10: Utilizza la classe di notifica integrata SlackMessage. Non è necessario alcun pacchetto aggiuntivo.

Laravel 11+: Il canale Slack integrato è stato rimosso. Il pacchetto rileva automaticamente questa situazione e invia webhook HTTP POST grezzi al tuo URL Slack. Non è necessario alcun pacchetto aggiuntivo. Se preferisci il canale di notifica completo, installa:```bash composer require laravel/slack-notification-channel

---

## Dashboard

<p align="center">
  <img src="https://assets.kitploit.com/production/public/readmes/12500/fc7950bd0cc6323bcc2d62b03e31c99edc7450b0ef76f9cbfa5133b527b25269.png" alt="Dashboard di rilevamento minacce — statistiche, timeline di 7 giorni, log delle minacce in tempo reale, IP più offensivi e minacce per paese" width="100%">
</p>

Il pacchetto include un dashboard integrato in modalità scura (Alpine.js + Tailwind CDN - nessun passaggio di build richiesto).```
+-------------------------------------------------------------------------+
|  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                                         |
+-------------------------------------------------------------------------+

Abilitare la dashboard

Aggiungi a .env:```env THREAT_DETECTION_DASHBOARD=true

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

### Accedere durante lo sviluppo locale

La dashboard utilizza il middleware `['web', 'auth']` per impostazione predefinita, quindi gli utenti devono aver effettuato l'accesso. Se la tua applicazione non dispone ancora di autenticazione, limitane l'accesso alla tua macchina:```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

Tutte le opzioni di guard, e il guard separato sugli endpoint che disabilitano i rilevamenti, sono trattati in Dashboard and API Authentication.

Se la dashboard mostra dati vuoti, la pagina è stata caricata ma le sue chiamate API no. Vedi API Authentication.


Endpoint API

Il pacchetto fornisce 15 endpoint REST per la creazione di dashboard o integrazioni personalizzate.

Autenticazione API

Le route API utilizzano il middleware auth:sanctum per impostazione predefinita. Il pacchetto gestisce questa situazione in modo elegante:

  • Sanctum installato: l'API richiede l'autenticazione tramite token Sanctum o autenticazione di sessione SPA.
  • Sanctum NON installato: il pacchetto rileva automaticamente che Sanctum è mancante e ripiega su ['api'] soltanto. L'API funziona senza autenticazione.

Se non usi Sanctum ma vuoi proteggere la tua API, hai due opzioni:

Opzione 1 - Usa il guard di autenticazione integrato:```env THREAT_DETECTION_API_GUARD=auth

**Opzione 2 - Modificare direttamente il middleware:**```php
// config/threat-detection.php
'api' => [
    'enabled' => true,
    'prefix' => 'api/threat-detection',
    'middleware' => ['api', 'auth'],  // or 'auth:your-guard'
],

Per test locali (se Sanctum blocca l'accesso), modificare temporaneamente:```php 'middleware' => ['api'], // remove 'auth:sanctum'

> Ripristina l'autenticazione prima di distribuire in produzione.

### Riferimento Endpoint

| Metodo | Endpoint | Descrizione |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Elenca le minacce (paginato, filtrabile) |
| GET | `/api/threat-detection/threats/{id}` | Dettagli di una singola minaccia |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Contrassegna la minaccia come falso positivo |
| GET | `/api/threat-detection/stats` | Statistiche generali |
| GET | `/api/threat-detection/summary` | Riepilogo dettagliato per tipo, livello, IP |
| GET | `/api/threat-detection/live-count` | Minacce nell'ultima ora |
| GET | `/api/threat-detection/by-country` | Raggruppate per paese |
| GET | `/api/threat-detection/by-cloud-provider` | Raggruppate per provider cloud |
| GET | `/api/threat-detection/top-ips` | IP più offensivi |
| GET | `/api/threat-detection/timeline` | Cronologia delle minacce (per grafici) |
| GET | `/api/threat-detection/ip-stats?ip=x.x.x.x` | Statistiche per un IP specifico |
| GET | `/api/threat-detection/correlation` | Analisi di correlazione |
| GET | `/api/threat-detection/export` | Esporta in CSV |
| GET | `/api/threat-detection/exclusion-rules` | Elenca le regole di esclusione |
| DELETE | `/api/threat-detection/exclusion-rules/{id}` | Elimina una regola di esclusione |

### Parametri di Query per `/threats`

| Parametro | Descrizione |
|-----------|-------------|
| `keyword` | Cerca in IP, URL, tipo |
| `ip` | Filtra per indirizzo IP |
| `level` | Filtra per livello di minaccia (`high`, `medium`, `low`) |
| `type` | Filtra per tipo di minaccia |
| `country` | Filtra per codice paese |
| `is_foreign` | Filtra IP esteri (`true`/`false`) |
| `cloud_provider` | Filtra per provider cloud |
| `is_false_positive` | Filtra per stato di falso positivo (`true`/`false`) |
| `date_from` / `date_to` | Filtro intervallo di date |
| `per_page` | Elementi per pagina (predefinito: 20, massimo: 100) |

### Esempio di Risposta 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
  }
}

Creazione di frontend personalizzati

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));
}, []);

Se la tua API utilizza auth:sanctum, includi gli header di autenticazione o configura l'autenticazione Sanctum SPA per le richieste basate su cookie.


Comandi 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

---

## Agire sui Dati (Blocco Lato Operatore)

Il pacchetto non blocca mai una richiesta — questa è la sua identità, non un comportamento predefinito. Gli export sopra
alimentano i livelli di enforcement che già esegui (fail2ban, nginx, un WAF perimetrale). Ma alcune distribuzioni
non hanno alcun livello di questo tipo da alimentare — hosting condiviso, PaaS, container dietro un load balancer che
non controlli. Per queste, il pacchetto espone le sue *decisioni* come helper, e tu scrivi il
middleware di enforcement da solo. Stessa architettura degli export: **noi forniamo
l'intelligence, tu fornisci il rifiuto.**```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);
    }
}

Prima di applicare restrizioni basate sull'IP, configura TrustProxies.

Tutto quanto sopra si basa su $request->ip(). Dietro un load balancer, una CDN o un reverse proxy, questo restituisce l'IP del client solo quando a Laravel viene indicato quali proxy considerare attendibili. In caso contrario, si rompono due cose contemporaneamente: ogni richiesta sembra provenire dal proxy, quindi una voce nella denylist blocca tutto il tuo traffico o niente affatto — e peggio ancora, se l'app si fida di un header inoltrato di cui non dovrebbe fidarsi, un attaccante imposta X-Forwarded-For e passa dritto attraverso la blocklist.

Questo è più importante qui che per whitelisted_ips. Una corrispondenza errata nella whitelist significa solo che il pacchetto analizza una richiesta che avrebbe potuto saltare: fallisce in modo sicuro. Una denylist usata per rifiutare il traffico fallisce in modo aperto — credi che un indirizzo sia bloccato quando non lo è. Controlla app/Http/Middleware/TrustProxies.php (o la chiamata trustProxies in bootstrap/app.php su Laravel 11+) prima di affidarti a uno dei due helper per l'applicazione delle restrizioni.

Registralo globalmente (prima del middleware di rilevamento va bene — gli helper leggono la configurazione e la cache, non dipendono dall'ordine dei middleware):```php // bootstrap/app.php (Laravel 11+) ->withMiddleware(function ($middleware) { $middleware->prepend(\App\Http\Middleware\EnforceThreatDecisions::class); })

Gli helper:

| Helper | Restituisce | Supportato da |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | configurazione `blocklisted_ips` (CIDR tramite `IpUtils`; la whitelist ha la precedenza) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | configurazione `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | il contatore di flood mantenuto dal middleware di rilevamento |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | quel contatore rispetto a `ddos.threshold` |

Note:

- **La denylist è statica e mantenuta dall'operatore.** Nulla nel pacchetto vi aggiunge mai
  voci — esegue la stessa decisione che prenderebbe una jail di fail2ban ("Ho letto la dashboard; questa /24
  è ostile"), solo all'interno dell'app.
- Il contatore DDoS conta solo le richieste che hanno raggiunto il rilevamento (`skip_paths`, IP
  in whitelist e ambienti disabilitati non vengono mai conteggiati), e rimane a 0 sui driver di cache
  in cui il rilevamento DDoS è disabilitato (`file`, `database`, `null`).
- Quando un client supera la soglia, viene anche inviato un [evento `DdosThresholdExceeded`](#ddosthresholdexceeded-event)
  — utile per l'allerting o per alimentare una lista di ban esterna. Non chiamare però `abort()`
  dal listener: i listener vengono eseguiti all'interno del `try/catch` fail-open del middleware di
  rilevamento, quindi il rifiuto appartiene al tuo middleware come sopra.

---

## Tracciamento delle sonde 404

Il pacchetto rileva le sonde di ricognizione - bot che colpiscono percorsi vulnerabili noti come `/wp-admin`, `/.env` o `/phpmyadmin` sul tuo sito non-WordPress e non-phpMyAdmin. Queste non hanno payload malevolo; il percorso stesso è il segnale.

Registrate con un tag di tipo `[probe]`, separatamente dal rilevamento basato sul payload. Se una richiesta di sonda contiene anche un payload malevolo, entrambi vengono registrati in modo indipendente.

Abilitato per impostazione predefinita con oltre 50 percorsi di sonda. Personalizzabile in `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...
    ],
],

Disabilita con THREAT_DETECTION_PROBE_TRACKING=false.


Campi sicuri (riduzione dei falsi positivi)

Se campi specifici di un form contengono legittimamente HTML, parole chiave SQL o codice (ad esempio editor CMS, input per frammenti di codice), puoi escluderli dalla scansione:```php // config/threat-detection.php 'safe_fields' => ['content', 'body', 'html', 'description', 'code'],

I campi elencati qui vengono rimossi dai parametri di query e dal corpo della richiesta - sia form-encoded che JSON (`application/json`) - prima che venga eseguito il rilevamento. Gli altri campi della stessa richiesta vengono comunque scansionati completamente.

### Percorsi sicuri (path-aware, per API JSON annidate)

`safe_fields` corrisponde a un nome di chiave **ovunque** esso compaia. Per le API JSON annidate questo è spesso troppo ampio — potresti voler esentare il valore di uno specifico campo senza esentare quella chiave ovunque. Usa `safe_paths`, che corrisponde tramite **percorso** in notazione con punti e supporta i wildcard di `fnmatch`:```php
// config/threat-detection.php
'safe_paths' => ['search.query', 'filters.*.value'],

Ad esempio, search.query esenta il valore di {"search": {"query": "..."}} (una casella di ricerca il cui testo contiene legittimamente parole come SELECT), mentre un campo query in qualsiasi altra posizione della richiesta viene comunque analizzato. Tutto ciò che non è elencato viene analizzato esattamente come prima.

Validator Post-Match (Riduzione dei Falsi Positivi con Consapevolezza del Checksum)

Una regex da sola non può esprimere ogni vincolo: qualsiasi sequenza di 12 cifre corrisponde al pattern Aadhaar, ma un vero numero Aadhaar supera anche il checksum Verhoeff. Mappa un'etichetta di pattern (predefinita o personalizzata) a un validator denominato e una corrispondenza regex conta come rilevamento solo quando almeno un valore corrispondente lo supera:```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],

Validator disponibili:

| Validator  | Checksum | Utilizzo tipico |
|------------|----------|-------------|
| `verhoeff` | Verhoeff | Numeri Aadhaar |
| `luhn`     | Luhn     | Numeri di carte di credito/debito |

Con la mappatura fornita, timestamp, id ordine e codici a barre che per caso sono lunghi 12 cifre non vengono più registrati come PII — mentre i numeri Aadhaar autentici continuano a esserlo. Se diversi valori corrispondono e solo uno supera il checksum, il rilevamento scatta comunque: un numero reale in mezzo al rumore è pur sempre una fuga di dati.

Abbina un validator al tuo pattern per il rilevamento delle carte con controllo del checksum:```php
'custom_patterns'    => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],

Un nome di validatore sconosciuto fallisce in modalità aperta — la corrispondenza viene conteggiata come non validata e viene registrato un avviso una sola volta — quindi un refuso non può mai disabilitare silenziosamente un pattern di rilevamento. Le configurazioni pubblicate prima di questa funzionalità semplicemente non hanno la chiave e mantengono il loro esatto comportamento attuale.


Redazione (Rilevare Non Significa Memorizzare)

Rilevare dati sensibili significava memorizzarli. Un modulo di profilo contenente un numero di cellulare, un PAN e un conto bancario avrebbe attivato tre pattern PII, e ciascuna delle tre righe scritte conservava l'intero corpo della richiesta alla lettera - mantenuto per l'intero periodo di conservazione, leggibile da chiunque abbia accesso alla dashboard o al database. Un valore in una query string finiva anche nella colonna url. Il rilevatore diventava una seconda copia concentrata di esattamente ciò di cui ti avverte.

Attivo per impostazione predefinita dalla v1.7.0. Quando viene attivato un pattern la cui etichetta è elencata, il valore corrispondente viene mascherato nel payload e nell'URL memorizzati:``` BODY: {"name":"Jane Doe","mobile":"[REDACTED]","pan":"[REDACTED]","bank_account":"[REDACTED]"}

L'alert, l'endpoint, i nomi dei campi e l'IP attaccante sopravvivono tutti - solo il valore scompare. La redazione viene eseguita *dopo* il rilevamento, quindi nulla viene perso.```php
// config/threat-detection.php
'redact' => [
    'enabled' => env('THREAT_DETECTION_REDACT', true),
    'mask'    => '[REDACTED]',
    'labels'  => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],

I payload di attacco vengono deliberatamente lasciati intatti - una stringa di injection è una prova, non un segreto, e mascherarla distruggerebbe l'indagine. Vengono toccate solo le etichette che elenchi.

Questo non sostituisce Safe Fields. Quelli impediscono che un campo venga scansionato; la redazione ti consente di continuare a scansionare e impedire la memorizzazione. Imposta THREAT_DETECTION_REDACT=false se hai bisogno dei payload completi per l'analisi forense.


Autenticazione della Dashboard e dell'API

La dashboard e l'API supportano guardie di autenticazione configurabili tramite .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

Le stesse opzioni sono disponibili per le route API con `THREAT_DETECTION_API_GUARD`.

Quando `guard=none` (predefinito), il pacchetto registra un avviso una volta al giorno per ricordarti di configurare l'autenticazione.

Il guard **fallisce in modo sicuro**: un valore di guard non riconosciuto (ad esempio un refuso) viene negato con un 403 e un avviso registrato anziché concedere silenziosamente l'accesso, e `guard=role` nega (con un avviso) quando il modello utente autenticato non ha un metodo `hasRole()`.

### Disabilitare un rilevamento richiede più dell'accesso in lettura

Contrassegnare una minaccia come falso positivo ed eliminare una regola di esclusione silenziano entrambi un tipo di rilevamento per tutti, il che è un privilegio diverso dalla lettura del log. Quei due endpoint vengono verificati rispetto a un guard separato:```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role

Si applica solo a quelle route, quindi la lettura e la dashboard si comportano esattamente come indicato da THREAT_DETECTION_API_GUARD. Senza di esso, qualsiasi utente autenticato della tua applicazione potrebbe disattivare un rilevamento.

Se il tuo modello utente non ha hasRole(), usa =auth. Per ripristinare il comportamento precedente alla 1.7.0 in cui qualsiasi utente autenticato poteva disabilitare i rilevamenti, usa =none - threat-detection:doctor avviserà finché è impostato.

Nota Dashboard ↔ API: la dashboard integrata recupera i suoi dati dalle route API utilizzando il cookie di sessione del browser. Se le tue route API sono protette con auth:sanctum, configura l'autenticazione stateful/SPA di Sanctum (oppure punta la dashboard verso una guard autenticata tramite cookie) in modo che quelle chiamate AJAX siano autorizzate - altrimenti la dashboard viene renderizzata vuota.


Pattern personalizzati

Aggiungi i tuoi pattern regex di rilevamento in config/threat-detection.php:```php 'custom_patterns' => [ '/your-regex-here/i' => 'Your Threat Label', ],

**Esempio - rilevare una sonda su un endpoint admin personalizzato:**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',

Forma array (opzioni per pattern)

Accanto alla classica forma stringa, il valore di un pattern può essere un array per il controllo completo:```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`** imposta direttamente il livello di minaccia invece di derivarlo dalle parole chiave di `threat_levels` nell'etichetta.
- **`contexts`** limita la scansione a segmenti specifici della richiesta — ad esempio un pattern per carte che ha senso solo nel body smette di corrispondere a sequenze di cifre negli header.
- **`validator`** indica un controllo inline post-match (vedi [Post-Match Validators](#post-match-validators-checksum-aware-false-positive-reduction)); ha la precedenza sulla mappa di etichette `pattern_validators`.

Le voci stringa e array si mescolano liberamente nella stessa configurazione. Le opzioni malformate **falliscono in modalità aperta** — il pattern continua a essere scansionato, senza restrizioni, e viene registrato un avviso — quindi un errore di configurazione non può mai disabilitare o restringere silenziosamente un rilevamento.

> **Nota:** Percorsi di probe comuni come `/wp-login.php`, `/.env`, `/phpmyadmin` sono ora gestiti automaticamente dalla funzionalità [404 Probe Tracking](#404-probe-tracking). Non sono necessari pattern personalizzati per questi.

Il livello di minaccia per ogni pattern è determinato automaticamente confrontando le parole chiave nell'etichetta con la configurazione `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'],
],

Se l'etichetta non corrisponde a nessuna parola chiave, la minaccia assume per impostazione predefinita la severità low.

I pattern regex non validi vengono automaticamente saltati e registrati come avvisi - non causeranno il crash della tua applicazione.


Utilizzo della Facade

Per l'accesso programmatico ai dati sulle minacce al di fuori del middleware:```php use JayAnta\ThreatDetection\Facades\ThreatDetection;

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

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

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

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

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

---

## Passaggio in Produzione

Il pacchetto è passivo per progettazione - non blocca, rifiuta o altera mai una richiesta, e il middleware di rilevamento avvolge l'intero corpo in `try/catch`, quindi un errore di rilevamento non può mai compromettere la tua applicazione. Viene fornito con impostazioni predefinite sensate e non necessita di servizi esterni per funzionare. Prima di andare in produzione, vale la pena dare un'occhiata a questa breve checklist:

1. **Proteggi la dashboard e l'API.** Entrambe hanno come impostazione predefinita `guard = none` per un primo avvio senza configurazione, e registrano un avviso giornaliero finché non sono protette. Prima della produzione, imposta una guardia - `THREAT_DETECTION_DASHBOARD_GUARD` e `THREAT_DETECTION_API_GUARD` (`auth`, `role`, o `ip`). Un valore non riconosciuto o una guardia `role` su un modello utente senza `hasRole()` ora **fallisce in modo sicuro** (403), quindi un errore di battitura non esporrà silenziosamente i dati. La disabilitazione di un rilevamento è controllata separatamente da `THREAT_DETECTION_API_WRITE_GUARD`, che ha come impostazione predefinita `role`. Vedi [Autenticazione Dashboard e API](#dashboard-and-api-authentication).
2. **Esegui le migrazioni** (`vendor:publish --tag=threat-detection-migrations && migrate`). Ripubblicare è sicuro - le migrazioni già pubblicate vengono saltate.
3. **Scegli una modalità di rilevamento.** `balanced` (predefinita) si adatta alla maggior parte delle applicazioni; usa `relaxed` per siti ricchi di contenuti, `strict` per superfici ad alta sicurezza. Regola con `content_paths`, `safe_fields`, e `min_confidence` - vedi [Riduzione dei Falsi Positivi](#reducing-false-positives).
4. **Rivedi i pattern PII regionali / personalizzati.** Le impostazioni predefinite sono incentrate sull'India (Aadhaar, PAN, IFSC) e i pattern numerici ampi (es. conto bancario) possono corrispondere a lunghi ID numerici al di fuori delle route di autenticazione. Sostituisci o riduci `custom_patterns` per la tua regione e applicazione, e aggiungi route con contenuti pesanti a `auth_paths` / `content_paths`.
5. **Attiva la conservazione** se prevedi volume elevato: `THREAT_DETECTION_RETENTION=true` (elimina automaticamente tramite lo scheduler). Richiede che lo scheduler di Laravel (`schedule:run`) sia gestito da cron.
6. **Extra opzionali, tutti disattivati per impostazione predefinita:** avvisi Slack (`THREAT_DETECTION_NOTIFICATIONS`), arricchimento geografico (`php artisan threat-detection:enrich` - l'unica funzionalità che effettua una chiamata in uscita, verso il servizio gratuito ip-api.com), e scritture in coda (`THREAT_DETECTION_QUEUE` - abilita solo se esegui già un queue worker; altrimenti le scritture sono sincrone e non richiedono Redis).

Nessun Redis, nessun queue worker e nessuna chiamata di rete in uscita sono richiesti per il rilevamento e la registrazione principali.

---

## Riduzione dei Falsi Positivi

Il pacchetto fornisce diversi strumenti per ridurre i falsi positivi. Usa quello che si adatta alla tua situazione:

### Campi Sicuri e Percorsi Sicuri

Escludi un campo dalla scansione completamente, sia per nome ovunque (`safe_fields`) che per percorso in notazione puntata per JSON annidati (`safe_paths`). L'approccio più semplice, e il più drastico - il campo viene saltato, quindi non viene eseguito alcun rilevamento su di esso.

Dettagli completi ed esempi: [Campi Sicuri](#safe-fields-false-positive-reduction).

### Soppressione dei Percorsi di Contenuto

Se hai editor CMS, moduli per post di blog, o sezioni commenti dove gli utenti inviano contenuti ricchi, quei percorsi spesso attivano falsi positivi (es. un post di blog contenente esempi di codice `<script>`). Aggiungi quei percorsi per sopprimere gli avvisi di livello basso/medio:```php
// config/threat-detection.php
'content_paths' => [
    'admin/posts/*',
    'admin/pages/*',
    'blog/*/edit',
    'comments',
],

Su questi percorsi, vengono registrate solo le minacce ad alta gravità.

Segnalazione di falsi positivi

Clicca il pulsante FP su qualsiasi minaccia nella dashboard per contrassegnarla come falso positivo. Questo:

  1. Contrassegna la minaccia come is_false_positive = true
  2. Crea automaticamente una regola di esclusione in modo che minacce simili dallo stesso URL/tipo vengano soppresse in futuro

Gestisci le regole di esclusione tramite API:```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}

### Assegnazione del punteggio di confidenza

Ogni minaccia riceve un punteggio di confidenza (0-100) basato su:
- Numero di corrispondenze di pattern nella stessa richiesta
- Gravità del pattern corrispondente
- Dove è stato trovato il pattern (query string > header > body)
- Se lo user-agent corrisponde a uno strumento di attacco noto
- Modalità di rilevamento corrente

Le minacce al di sotto della soglia di confidenza per la tua modalità di rilevamento non vengono registrate (vedi [Modalità di rilevamento](#detection-modes)).

---

## Tipi di attacco rilevati

| Categoria | Esempi |
|----------|---------|
| **SQL Injection** | UNION, boolean, time-based, codifica CHAR, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), operazioni su file (INTO OUTFILE, LOAD_FILE), enumerazione ORDER BY, stringhe esadecimali, UNHEX |
| **NoSQL Injection** | Operatori MongoDB $ne, $gt, $regex, $where |
| **XSS** | Tag script, gestori di eventi SVG (`<svg onload=`), gestori di eventi HTML (`<body onload=`, `<img onerror=`), espressioni CSS, URI JavaScript, manipolazione DOM |
| **Esecuzione di codice** | Funzioni shell RCE, deserializzazione PHP, deserializzazione Java (base64 + hex magic bytes), template injection (Blade, JSP, ASP, Jinja2, Velocity), eval(), decodifica base64, PHP assert(), create_function(), preg_replace /e |
| **SSTI** | Sonde matematiche (`{{7*7}}`), import/config Jinja2, template Velocity, Expression Language |
| **Command Injection** | Linux (funzioni shell, catene di comandi, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Accesso ai file** | Directory traversal, protocolli LFI/RFI, sonde su file sensibili (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), metadata AWS/GCP, IP privati, localhost codificato in hex/decimale, DNS rebinding (xip.io, nip.io, sslip.io) |
| **LDAP Injection** | Manipolazione di filtri LDAP, iniezione OR |
| **XPath Injection** | Selettori di attributi, funzioni XPath (contains, substring) |
| **CRLF / Header Injection** | CRLF codificato in URL (`%0d%0a`), iniezione LF, iniezione null byte |
| **Attacchi a protocolli** | HTTP request smuggling (CL+TE), SSI injection |
| **Exploit CVE** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Tracciamento sonde** | WordPress (`/wp-admin`, `/wp-login.php`), file di configurazione (`/.env`, `/.git`), strumenti database (`/phpmyadmin`), sonde tecnologiche (`.asp`, `.jsp`), Spring actuator, Swagger/API docs - 50+ percorsi |
| **Scanner** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei e oltre 20 altri (53 in totale) |
| **AI Scrapers** | GPTBot, ClaudeBot, ChatGPT, ByteSpider, Cohere, Common Crawl |
| **Browser headless** | HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright |
| **Bot** | Script Python, client HTTP Go, cURL, wget, AhrefsBot, SEMRushBot, user agent vuoti |
| **Autenticazione** | Rilevamento brute force, perdita di token, esposizione di password, esposizione di session ID |
| **DDoS** | Rilevamento di richieste eccessive basato sulla frequenza |
| **Evasione** | Inserimento di commenti SQL, doppia codifica URL, codifica di entità HTML, escape Unicode, IIS Unicode, escape esadecimali |
| **Altro** | GraphQL introspection, prototype pollution, open redirect, XXE, web shell, crypto mining, rilevamento PII |

---

## Esecuzione della suite di test```bash
composer test

Il pacchetto include 1.857 test (4.950 asserzioni) che coprono pattern di rilevamento, comportamento del middleware, endpoint API, punteggio di confidenza, regole di esclusione, rilevamento DDoS, resistenza all'evasione, pattern CVE, iniezione LDAP/XPath/SSTI, rilevamento bot/scanner, tracciamento delle sonde, comandi di esportazione, autenticazione della dashboard, campi sicuri, ottimizzazioni delle prestazioni e verifica full-cycle HTTP-to-DB.


Licenza

Licenza MIT. Vedi LICENSE per i dettagli.

Contribuire

I contributi sono benvenuti! Invia una Pull Request.

Crediti

Categorie