
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.
Rilevamento passivo delle intrusioni per Laravel — osserva ogni injection SQL, XSS, scanner e sonda bot che colpisce la tua app, registrata con pieno contesto. È un IDS, non un WAF: non blocca, filtra o modifica mai una richiesta.
Aggiungilo a qualsiasi app Laravel 10–13 e inizierà a scansionare ogni richiesta HTTP confrontandola con oltre 150 pattern di attacco, valutando ogni corrispondenza in base alla confidenza e scrivendola nel tuo database — con una dashboard integrata, avvisi Slack, arricchimento geografico ed esportazioni fail2ban/blocklist. Nessuna richiesta viene mai bloccata. Pensalo come una telecamera di sicurezza, non come un lucchetto: ti mostra esattamente chi sta sondando le tue route, con che frequenza e con quali tecniche.
Estratto da un'app in produzione e testato sul traffico reale. 335 test, nessuna dipendenza runtime oltre a Laravel stesso, e nessuna connessione internet richiesta per il rilevamento.
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+, oppure `app/Http/Kernel.php` su Laravel 10) — snippet completo in [Guida rapida](#quick-start) di seguito. Tutto qui; il rilevamento è attivo.```bash
php artisan threat-detection:doctor # confirms it is actually recording
Questo pacchetto è un IDS passivo a livello applicativo — osserva e registra, non blocca. È pensato per stare accanto a un WAF o a un servizio edge, non per sostituirli. Ogni livello vede qualcosa che gli altri non vedono:
In breve: un edge/WAF è la serratura sulla porta; questo è la telecamera di sicurezza dentro, con il contesto applicativo per dirti esattamente cosa viene tentato su quale rotta, da chi e con quale frequenza. Usalo per alimentare decisioni reali — ban di fail2ban, limiti di frequenza, geoblocco — con dati che il tuo livello edge non vede mai.
La domanda più comune su un rilevatore che non blocca mai. Quattro risposte, in ordine crescente di impegno:
Il pacchetto fornisce l'intelligenza; 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 potrà mai mandare giù il tuo sito.
threat_logs con IP, URL, tipo di minaccia, livello di gravità e punteggio di confidenzaNon è necessaria una connessione Internet per il rilevamento.
composer require jayanta/laravel-threat-detection
### 2. Pubblica le migrazioni ed eseguile
> **Questo passaggio è obbligatorio.** Senza di esso, il pacchetto rileverà le minacce ma non potrà memorizzarle nel database. Se salti questo passaggio, la tabella `threat_logs` non esisterà e tutte le rilevazioni andranno perse silenziosamente (vedrai solo errori in `storage/logs/laravel.log`).```bash
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate
Questo crea due tabelle: threat_logs (archivia le minacce rilevate) e threat_exclusion_rules (archivia le regole dei 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` - tutte dovrebbero mostrare `Ran`.
### 3. Registra il middleware
Il middleware è ciò che scansiona le richieste. Devi aggiungerlo al tuo gruppo 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 --versionnel 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) Pubblica il file di configurazione```bash
php artisan vendor:publish --tag=threat-detection-config
Il pacchetto funziona con impostazioni predefinite sensate. Pubblicare la configurazione ti consente di personalizzare i modelli di rilevamento, le modalità di sensibilità, le notifiche Slack e altro ancora. Se salti questo passaggio, tutto funziona comunque.
Tutto qui. La tua app ora sta rilevando le minacce.
Dopo l'installazione, innesca una minaccia di prova e conferma che sia stata registrata.
php artisan serve
### Passo 2: Apri un URL di test nel tuo browser
Aggiungi un parametro di query dannoso a **qualsiasi route esistente** nella tua app (la tua homepage, una pagina prodotto, ecc.). Per esempio:
**SQL Injection:**```
http://localhost:8000/?q=' UNION SELECT * FROM users--
XSS (Cross-Site Scripting):``` http://localhost:8000/?q=
**Directory Traversal:**```
http://localhost:8000/?file=../../etc/passwd
RCE (Esecuzione remota di codice):``` http://localhost:8000/?cmd=system('ls -la')
**Shellshock (CVE-2014-6271):**```
http://localhost:8000/?cmd=() { :;}; /bin/bash
Iniezione di comandi in Windows:``` http://localhost:8000/?cmd=powershell -c whoami
**DROP TABLE (SQL DDL):**```
http://localhost:8000/?q=DROP TABLE users
Usa una rotta che esista effettivamente nella tua app (come
/). Se l'URL restituisce un 404, il middleware potrebbe non essere stato eseguito.
Opzione A - Comando Artisan (più rapido):```bash php artisan threat-detection:stats
Dovresti vedere una tabella con `Total Threats`, conteggi di gravità e IP principali.
**Opzione B - Tinker:**```bash
php artisan tinker
DB::table('threat_logs')->latest()->take(5)->get(['ip_address', 'type', 'threat_level', 'confidence_score']);
Opzione C - file di log 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 solo una 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 | Usare `curl` registra anche un rilevamento user-agent "cURL Command" (severità bassa). È 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 Slack necessaria | Le notifiche sono disattivate per impostazione predefinita. |
| Nessuna connessione internet necessaria | Il rilevamento principale è locale al 100%. Solo il comando opzionale `threat-detection:enrich` chiama un'API esterna per i dati geo. |
### Risoluzione dei problemi
**Inizia da qui: un solo comando risponde alla maggior parte delle domande:**```bash
php artisan threat-detection:doctor
Controlla le cose che fanno fallire il rilevamento silenziosamente — dove la dashboard rimane vuota, che sembra identico a "nessun attacco" — e stampa la correzione esatta per ciascuna. Esce con un codice non zero in caso di errore reale, quindi è sicuro eseguirlo 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 rotta o a un gruppo; configurazione pubblicata che precede questa versione; pattern personalizzati che oscurano quelli integrati; un driver di cache che non può effettuare 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 salvate nel database"**
Se il doctor ha dato esito positivo, l'installazione è corretta e il problema è la richiesta di test stessa. Tre cose che non può verificare per te:
| Controllo | Come verificarlo |
|-------|---------------|
| IP non in whitelist | Se hai aggiunto `THREAT_DETECTION_WHITELISTED_IPS` al `.env`, rimuovilo durante il test |
| Hai usato una rotta esistente | L'URL di test deve corrispondere a una rotta reale (es. `/`). Un 404 significa che il middleware non è mai stato eseguito |
| Cache di deduplicazione | Stesso IP + stesso tipo di attacco viene memorizzato in cache per 5 minuti - prova un tipo di attacco diverso |
> Eseguire `php artisan migrate` da solo non è mai sufficiente: i file di migrazione si trovano
> all'interno del pacchetto e devono essere pubblicati nella cartella `database/migrations/`
> prima. Il doctor stampa il comando esatto quando questo è il problema.
**"L'API restituisce 401 Unauthorized"**
Vedi [Autenticazione API](#api-authentication) qui sotto.
**"La dashboard mostra 404"**
La dashboard è disabilitata per impostazione predefinita. Aggiungi `THREAT_DETECTION_DASHBOARD=true` al `.env` e cancella la cache delle rotte:```bash
php artisan route:clear
/wp-admin, /.env, /phpmyadmin, /actuator, ecc.) con 50+ percorsi di sonda predefinitiapplication/json)Il pacchetto funziona senza alcuna modifica al file .env. Tutti i valori seguenti sono opzionali - aggiungili solo se vuoi sovrascrivere i valori predefiniti.```env
THREAT_DETECTION_ENABLED=true
THREAT_DETECTION_MODE=balanced
### Modalità di rilevamento
| Modalità | Soglia di confidenza | Comportamento |
|------|---------------------|----------|
| `strict` | 0 (registra tutto) | Tutti i pattern attivi, soglie minime. Cattura tutto ma potrebbe segnalare traffico legittimo. |
| `balanced` | 10 | Predefinita. Punteggio di confidenza attivo, soglie standard. Adatta alla maggior parte delle app. |
| `relaxed` | 40 | Solo i pattern ad alta gravità attivano. Ideale per siti con molti contenuti 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 nell'elenco sopra) oppure aggiungi al tuo phpunit.xml:```xml
### Riferimento Configurazione
Pubblica il file di configurazione per vedere tutte le opzioni disponibili:```bash
php artisan vendor:publish --tag=threat-detection-config
Sezioni di configurazione chiave: skip_paths (percorsi da saltare), only_paths (modalità whitelist), auth_paths (rilevamento intelligente per rotte di login), content_paths (sopprime gli avvisi non critici), safe_fields (esclude campi specifici dalla scansione), safe_paths (esclusione di campi basata sul percorso per JSON annidati), probe_tracking (rilevamento probe 404), context_weights (moltiplicatori di punteggio), threat_levels (mappatura delle parole chiave di gravità), api_route_filtering (sopprime basso/medio sulle rotte API), queue (elaborazione asincrona), retention (pulizia automatica), max_detections_per_request (limite di prestazioni), / (modalità autenticazione).
only_paths)Se la tua applicazione ha molte rotte ma ti interessano solo alcune, usa only_paths per scansionare solo quelle rotte. Tutte le altre rotte vengono saltate automaticamente - nessun overhead middleware.```php
// config/threat-detection.php
'only_paths' => [
'admin/',
'api/',
'login',
'register',
],
Lasciare vuoto (predefinito) per analizzare tutte le rotte (soggetto a `skip_paths`). Quando entrambi sono configurati, `only_paths` viene controllato per primo, quindi `skip_paths` si applica all'interno del set corrispondente.
### Supporto alle code
Per impostazione predefinita, la registrazione delle minacce avviene in modo sincrono nel ciclo di richiesta. Per le applicazioni ad alto traffico, puoi scaricare le scritture del database 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 viene differita.
Elimina automaticamente i vecchi log delle minacce 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 ogni giorno alle 02:00 tramite `threat-detection:purge`.
### Evento ThreatDetected
Ogni minaccia confermata emette un evento `ThreatDetected` a cui puoi metterti in ascolto:```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 database), $ipAddress e $threatLevel. Usalo per attivare azioni personalizzate - inviare avvisi Telegram, aggiornare una blocklist, alimentare un SIEM, ecc.
Quando un client supera la soglia DDoS configurata (ddos.threshold richieste entro
ddos.window secondi), viene generato un evento DdosThresholdExceeded insieme alla voce di
log delle minacce:```php
use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;
protected $listen = [ DdosThresholdExceeded::class => [ YourFloodListener::class, ], ];
L'evento trasporta `$ipAddress`, `$requestCount`, `$threshold` e `$windowSeconds`. Viene
limitato a una volta per IP per finestra di deduplicazione (stessa limitazione della riga di log), quindi un flood non può
sovrastare i tuoi listener. Usalo per gli avvisi o per alimentare un archivio di ban esterno; per *rifiutare*
i client oltre soglia, usa `ThreatDetection::isDdosThresholdExceeded($ip)` dal tuo
middleware — vedi [Agire sui dati](#acting-on-the-data-operator-side-blocking).
---
## Notifiche Slack
Le notifiche Slack sono disabilitate per impostazione predefinita. Per abilitarle:```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts
Per impostazione predefinita, solo le minacce ad alta gravità attivano le notifiche (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
Il pacchetto include una dashboard integrata in modalità scura (Alpine.js + Tailwind CDN - non è richiesto alcun passaggio di build).```
+-------------------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------------------+
Aggiungi a .env:```env
THREAT_DETECTION_DASHBOARD=true
Visita: `http://your-app.test/threat-detection`
### Accesso durante lo sviluppo locale
Il dashboard utilizza il middleware `['web', 'auth']` per impostazione predefinita, quindi gli utenti devono aver effettuato l'accesso. Se la tua app non ha ancora un'autenticazione, limitane l'accesso alla tua macchina locale:```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1
Tutte le opzioni di guard, e la guard separata sugli endpoint che disabilitano i rilevamenti, sono trattate in Dashboard e autenticazione API.
Se la dashboard mostra dati vuoti, la pagina è stata caricata ma le sue chiamate API no. Vedi Autenticazione API.
Il pacchetto fornisce 15 endpoint REST per creare dashboard o integrazioni personalizzate.
Le rotte API utilizzano il middleware auth:sanctum per impostazione predefinita. Il pacchetto gestisce questo in modo elegante:
['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 i test locali (se Sanctum blocca l'accesso), modifica temporaneamente:```php 'middleware' => ['api'], // remove 'auth:sanctum'
> Ripristina l'autenticazione prima di distribuire in produzione.
### Riferimento Endpoint
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Elenca le minacce (impaginate, filtrabili) |
| 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` | Ripartizione dettagliata 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 principali responsabili |
| 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`
| Parameter | Description |
|-----------|-------------|
| `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 (default: 20, max: 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
}
}
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 le intestazioni di autenticazione oppure configura l'autenticazione SPA di Sanctum per le richieste basate su cookie.
php artisan threat-detection:doctor
php artisan threat-detection:stats
php artisan threat-detection:enrich --days=7
php artisan threat-detection:purge --days=30
php artisan threat-detection:export-fail2ban --level=high --since=24h --min-hits=5 php artisan threat-detection:export-fail2ban --format=plain > /tmp/banlist.txt
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 di cui sopra
alimentano i layer di enforcement che già esegui (fail2ban, nginx, un WAF perimetrale). Ma alcune distribuzioni
non hanno alcun layer 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 scrivi tu il
middleware di enforcement. Stessa architettura degli export: **noi forniamo l'intelligence, tu la decisione di 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 regole basate sull'IP, configura
TrustProxies.Tutto quanto sopra si basa su
$request->ip(). Dietro un load balancer, CDN o reverse proxy, questo restituisce l'IP client solo quando Laravel sa quali proxy considerare attendibili. Se non lo sa, due cose si rompono in una volta: ogni richiesta sembra provenire dal proxy, quindi una voce nella denylist blocca tutto il traffico o niente — e peggio, se l'app si fida di un header inoltrato che non dovrebbe, un attaccante impostaX-Forwarded-Fore 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 open — credi che un indirizzo sia bloccato quando non lo è. Controllaapp/Http/Middleware/TrustProxies.php(o la chiamatatrustProxiesinbootstrap/app.phpsu Laravel 11+) prima di fare affidamento su uno dei due helper per l'applicazione.
Registralo globalmente (prima del middleware di rilevamento va bene — gli helper leggono config e 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 | Basato su |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | config `blocklisted_ips` (CIDR tramite `IpUtils`; la whitelist ha la precedenza) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | config `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | il contatore di flood che il middleware di rilevamento mantiene |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | quel contatore rispetto a `ddos.threshold` |
Note:
- **La denylist è statica e gestita dall'operatore.** Il pacchetto non vi aggiunge mai
nulla: esegue la stessa decisione che prenderebbe una jail di fail2ban ("Ho letto la dashboard; questo /24
è ostile"), solo in-app.
- Il contatore DDoS conta solo le richieste che hanno raggiunto il rilevamento (`skip_paths`, IP in
whitelist ed environment disabilitati non vengono mai contati), e resta a 0 sui driver di cache dove
il rilevamento DDoS è disabilitato (`file`, `database`, `null`).
- Quando un client supera la soglia, viene anche inviato un evento [`DdosThresholdExceeded`](#ddosthresholdexceeded-event)
— utile per generare alert o alimentare una lista di ban esterna. Non chiamare `abort()`
dal listener, però: i listener vengono eseguiti all'interno del `try/catch` fail-open
del middleware di rilevamento, quindi il rifiuto spetta al tuo middleware come sopra.
---
## Tracciamento Probe 404
Il pacchetto rileva i probe di ricognizione - bot che colpiscono percorsi vulnerabili noti come `/wp-admin`, `/.env` o `/phpmyadmin` sul tuo sito non-WordPress e non-phpMyAdmin. Questi non contengono payload maliziosi; il percorso stesso è il segnale.
Vengono registrati con un tag di tipo `[probe]`, separati dal rilevamento basato sul payload. Se una richiesta di probe contiene anche un payload malizioso, entrambi vengono registrati indipendentemente.
Abilitato di default con 50+ percorsi di probe. Personalizza 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...
],
],
Disattiva con THREAT_DETECTION_PROBE_TRACKING=false.
Se specifici campi di modulo contengono legittimamente HTML, parole chiave SQL o codice (ad es., editor CMS, input di snippet 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 sulla stessa richiesta vengono comunque scansionati completamente.
### Safe Paths (path-aware, per API JSON nidificate)
`safe_fields` corrisponde a un nome di chiave **ovunque** appaia. Per le API JSON nidificate questo è spesso troppo ampio: potresti voler esentare il valore di un campo specifico senza esentare quella chiave ovunque. Usa `safe_paths`, che corrisponde per **percorso** in notazione a punti e supporta i caratteri jolly `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 parte della richiesta viene ancora scansionato. Tutto ciò che non è elencato viene scansionato esattamente come prima.
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 di Verhoeff. Mappa un'etichetta di pattern (predefinita o personalizzata) a un validatore denominato e una corrispondenza regex viene conteggiata come rilevamento solo quando almeno un valore corrispondente lo supera:```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],
Validatori disponibili:
| Validator | Checksum | Uso tipico |
|------------|----------|-------------|
| `verhoeff` | Verhoeff | Numeri Aadhaar |
| `luhn` | Luhn | Numeri di carte di credito/debito |
Con la mappatura inclusa, timestamp, ID ordine e codici a barre che hanno per caso 12 cifre non vengono più registrati come PII — mentre i numeri Aadhaar genuini lo sono ancora. Se più valori corrispondono e solo uno supera il checksum, il rilevamento scatta comunque: un numero reale in mezzo al rumore è comunque una fuga di dati.
Abbina un validatore al tuo pattern personale per il rilevamento delle carte basato su checksum:```php
'custom_patterns' => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],
Un nome di validatore sconosciuto apre in fail-open — il riscontro viene conteggiato senza convalida e un avviso viene registrato una sola volta — quindi un refuso non può mai disattivare silenziosamente un pattern di rilevamento. Le configurazioni pubblicate prima di questa funzionalità semplicemente non hanno la chiave e mantengono esattamente il comportamento attuale.
Rilevare dati sensibili una volta significava memorizzarli. Un modulo di profilo contenente un numero di cellulare, un PAN e un conto bancario farebbe scattare tre pattern PII, e ciascuna delle tre righe scritte conservava l'intero corpo della richiesta parola per parola - conservato per l'intero periodo di conservazione, leggibile da chiunque abbia accesso alla dashboard o al database. Anche un valore in una query string finiva nella colonna url. Il rilevatore diventava una seconda copia concentrata di ciò di cui ti mette in guardia.
Attivo per impostazione predefinita dalla v1.7.0. Quando un pattern la cui etichetta è elencata si attiva, il valore che ha rilevato 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 dell'attaccante sopravvivono tutti - solo il valore viene rimosso. La redazione viene eseguita *dopo* il rilevamento, quindi non viene perso nulla.```php
// config/threat-detection.php
'redact' => [
'enabled' => env('THREAT_DETECTION_REDACT', true),
'mask' => '[REDACTED]',
'labels' => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],
Attack payloads are 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 Campi sicuri. Questi impediscono che un campo venga scansionato; la redazione consente di continuare a scansionare ma smettere di archiviare. Imposta
THREAT_DETECTION_REDACT=falsese hai bisogno dei payload completi per la forensica.
La dashboard e l'API supportano guardie di autenticazione configurabili tramite .env:```env
THREAT_DETECTION_DASHBOARD_GUARD=auth
THREAT_DETECTION_DASHBOARD_GUARD=role THREAT_DETECTION_DASHBOARD_ROLE=admin
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 rotte 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.
La guardia **fallisce in modalità chiusa**: un valore di guardia non riconosciuto (ad es. un refuso) viene negato con un 403 e un avviso registrato, piuttosto che consentire l'accesso silenziosamente, e `guard=role` nega (con un avviso) quando il modello utente autenticato non ha un metodo `hasRole()`.
### Disattivare una rilevazione richiede più del solo accesso in lettura
Contrassegnare una minaccia come falso positivo ed eliminare una regola di esclusione silenziano entrambi un tipo di rilevazione per tutti, il che è un privilegio diverso dalla lettura del registro. Questi due endpoint vengono controllati da una guardia separata:```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 pre-1.7.0 in cui qualsiasi utente autenticato poteva disabilitare i rilevamenti, usa =none - threat-detection:doctor mostrerà un avviso finché è impostato.
Nota su Dashboard ↔ API: la dashboard integrata recupera i 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 indica alla dashboard un guard autenticato via cookie) in modo che quelle chiamate AJAX siano autorizzate - altrimenti la dashboard viene renderizzata vuota.
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 per endpoint admin personalizzato:**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',
Oltre alla classica forma a stringa, il valore di un pattern può essere un array per un 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 `threat_levels` nell'etichetta.
- **`contexts`** limita la scansione a segmenti specifici della richiesta — ad esempio un pattern di carta che ha senso solo nel body smette di far corrispondere sequenze di cifre negli header.
- **`validator`** indica un controllo post-match inline (vedi [Validatori post-match](#post-match-validators-checksum-aware-false-positive-reduction)); ha precedenza sulla mappa `pattern_validators` dell'etichetta.
Le voci stringa e array si mescolano liberamente nella stessa configurazione. Le opzioni malformate **fail open** — il pattern continua a scansionare, senza restrizioni, e viene registrato un avviso — quindi un errore di configurazione non può mai disabilitare o restringere silenziosamente una rilevazione.
> **Nota:** I percorsi di probe comuni come `/wp-login.php`, `/.env`, `/phpmyadmin` sono ora gestiti automaticamente dalla funzionalità [Tracciamento dei probe 404](#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 viene impostata per impostazione predefinita sulla gravità low.
I pattern regex non validi vengono automaticamente saltati e registrati come avvisi - non faranno crashare la tua applicazione.
Per l'accesso programmatico ai dati delle 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');
---
## Passare alla Produzione
Il pacchetto è passivo per progettazione - non blocca, rifiuta o altera mai una richiesta, e il middleware di rilevamento avvolge tutto il corpo in `try/catch`, quindi un errore di rilevamento non può mai rompere la tua applicazione. Viene fornito con impostazioni predefinite sensate e non richiede 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 sono impostate di default su `guard = none` per un primo avvio senza configurazione e registrano un avviso giornaliero finché sono non 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 modalità chiusa** (403), quindi un errore di battitura non esporrà silenziosamente i dati. La disattivazione di un rilevamento è limitata separatamente da `THREAT_DETECTION_API_WRITE_GUARD`, che per impostazione predefinita è `role`. Vedi [Autenticazione di Dashboard e API](#dashboard-and-api-authentication).
2. **Esegui le migrazioni** (`vendor:publish --tag=threat-detection-migrations && migrate`). La ripubblicazione è sicura - le migrazioni già pubblicate vengono saltate.
3. **Scegli una modalità di rilevamento.** `balanced` (predefinita) si adatta alla maggior parte delle app; usa `relaxed` per siti ricchi di contenuti, `strict` per superfici ad alta sicurezza. Ottimizza con `content_paths`, `safe_fields` e `min_confidence` - vedi [Ridurre i Falsi Positivi](#reducing-false-positives).
4. **Rivedi i pattern PII regionali / personalizzati.** I valori predefiniti sono incentrati 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 taglia `custom_patterns` per la tua regione e applicazione, e aggiungi le route ad alto contenuto a `auth_paths` / `content_paths`.
5. **Attiva la conservazione** se prevedi volumi: `THREAT_DETECTION_RETENTION=true` (pulizia automatica tramite lo scheduler). Richiede che lo scheduler di Laravel (`schedule:run`) sia pilotato 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, al servizio gratuito ip-api.com), e scritture in coda (`THREAT_DETECTION_QUEUE` - abilita solo se esegui già un worker per le code; altrimenti le scritture sono sincrone e non richiedono Redis).
Per il rilevamento e la registrazione di base non sono richiesti Redis, worker per le code o chiamate di rete in uscita.
---
## Ridurre i 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`) sia tramite percorso in notazione a punti per JSON annidati (`safe_paths`). L'approccio più semplice, e il più drastico - il campo viene saltato, quindi su di esso non viene eseguito alcun rilevamento.
Dettagli completi ed esempi: [Campi Sicuri](#safe-fields-false-positive-reduction).
### Soppressione dei Percorsi di Contenuto
Se hai editor CMS, moduli di post per blog o sezioni di commenti in cui gli utenti inviano contenuti ricchi, quei percorsi spesso generano falsi positivi (es. un post di blog contenente esempi di codice `<script>`). Aggiungi quei percorsi per sopprimere gli avvisi bassi/medi:```php
// config/threat-detection.php
'content_paths' => [
'admin/posts/*',
'admin/pages/*',
'blog/*/edit',
'comments',
],
Su questi percorsi, vengono registrate solo minacce ad alta gravità.
Fai clic sul pulsante FP su qualsiasi minaccia nella dashboard per contrassegnarla come falso positivo. Questo:
is_false_positive = trueGestisci le regole di esclusione tramite API:```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}
### 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 > headers > 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, booleano, basato sul tempo, 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 di script, gestori di eventi SVG (`<svg onload=`), gestori di eventi HTML (`<body onload=`, `<img onerror=`), espressioni CSS, URI JavaScript, manipolazione del DOM |
| **Esecuzione di codice** | funzioni di shell RCE, deserializzazione PHP, deserializzazione Java (byte magici base64 + hex), iniezione di template (Blade, JSP, ASP, Jinja2, Velocity), eval(), decodifica base64, assert() PHP, create_function(), preg_replace /e |
| **SSTI** | Sonde matematiche (`{{7*7}}`), import/config di Jinja2, template Velocity, Expression Language |
| **Iniezione di comandi** | Linux (funzioni di shell, catene di comandi, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Accesso ai file** | Attraversamento di directory, protocolli LFI/RFI, sonde di file sensibili (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), metadati AWS/GCP, IP privati, localhost codificato in hex/decimale, DNS rebinding (xip.io, nip.io, sslip.io) |
| **Iniezione LDAP** | Manipolazione di filtri LDAP, iniezione OR |
| **Iniezione XPath** | Selettori di attributi, funzioni XPath (contains, substring) |
| **CRLF / Iniezione di header** | CRLF codificato in URL (`%0d%0a`), iniezione LF, iniezione di byte nulli |
| **Attacchi di protocollo** | HTTP request smuggling (CL+TE), iniezione SSI |
| **Exploit CVE** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Tracciamento dei probe** | WordPress (`/wp-admin`, `/wp-login.php`), file di configurazione (`/.env`, `/.git`), strumenti di database (`/phpmyadmin`), sonde tecnologiche (`.asp`, `.jsp`), Spring actuator, documentazione Swagger/API - 50+ percorsi |
| **Scanner** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei e altri 20+ (53 in totale) |
| **Scraper IA** | 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 di brute force, perdite 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 entità HTML, escape Unicode, IIS Unicode, escape hex |
| **Altro** | Introspezione GraphQL, prototype pollution, open redirect, XXE, web shell, crypto mining, rilevamento di PII |
---
## Esecuzione della suite di test```bash
composer test
The package includes 335 tests (856 assertions) covering detection patterns, middleware behavior, API endpoints, confidence scoring, exclusion rules, DDoS detection, evasion resistance, CVE patterns, LDAP/XPath/SSTI injection, bot/scanner detection, probe tracking, export commands, dashboard auth, safe fields, performance optimizations, and full-cycle HTTP-to-DB verification.
Licenza MIT. Vedi LICENSE per i dettagli.
I contributi sono benvenuti! Invia una Pull Request.
| Questo pacchetto (IDS applicativo) | WAF (mod_security, Cloudflare WAF) | Edge / CDN (Cloudflare) |
|---|
| Blocca richieste dannose | ❌ solo log | ✅ | ✅ |
| Contesto applicativo completo (rotta esatta, payload decodificato, utente autenticato) | ✅ | ⚠️ parziale | ❌ |
| Dashboard integrata + log delle minacce nel tuo DB | ✅ | ⚠️ varia | ⚠️ 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 | ✅ |
| Installazione | un composer require | medio–alto | basso–medio |
| Costo | gratuito, MIT | varia | piano gratuito + a pagamento |
| Cosa vuoi fare | Usa | Impegno |
|---|
| Vedere cosa ti sta colpendo | La dashboard o threat-detection:stats | nessuno, è già in esecuzione |
| Bannare i recidivi sul firewall | threat-detection:export-fail2ban — passalo a un cron | una riga |
| Negare a livello di web server | threat-detection:export-blocklist → direttive nginx/apache | una riga |
| Rifiutare le richieste nell'app | Helper lato operatore — isBlocklisted(), isDdosThresholdExceeded() | ~10 righe di middleware tuo |
| Reagire in tempo reale | L'evento ThreatDetected — Telegram, SIEM, PagerDuty | un listener |
strict, balanced (predefinita) e relaxed - sensibilità regolabiledashboard.guardapi.guard