
laravel-threat-detection v1.7.2
Passive Laravel-Middleware, die SQL-Injection, XSS, RCE, Bot-Scanner und über 175 Angriffsmuster erkennt und protokolliert. Verfügt über ein integriertes Dashboard, Slack-Benachrichtigungen, REST-API und Geo-Anreicherung. IDS, kein WAF.
Laravel Threat Detection
Sicherheitsüberwachung und Angriffsprotokollierung für Laravel. Erkennen und protokollieren Sie SQL-Injection,
XSS, RCE, Directory Traversal, Bot-Scanner und /wp-admin-artige Recon-Sonden —
jede feindselige Anfrage wird mit vollständigem Anwendungskontext in Ihrer Datenbank aufgezeichnet.
Es ist ein IDS, kein WAF: Es blockiert, filtert oder verändert niemals eine Anfrage.
Sind Sie hier, weil Sie so etwas gesehen haben?```
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
Diese Anfragen erreichen deine Laravel-App bereits. Dein Access-Log zeigt die URL
und den Statuscode — und sonst nichts: nicht den dekodierten Payload, nicht welche deiner
Routen angegriffen wurde, nicht ob dieselbe IP in dieser Stunde vierzig andere Dinge versucht hat.
Dieses Paket beantwortet diese Fragen. Füge es in eine beliebige Laravel-10–13-App ein, und es beginnt,
jede HTTP-Anfrage gegen über 150 Angriffsmuster zu prüfen, jede Übereinstimmung nach
Konfidenz zu bewerten und in deine Datenbank zu schreiben — mit einem integrierten Dashboard, Slack-Benachrichtigungen,
Geo-Anreicherung und fail2ban/Blocklisten-Exporten. Keine Anfrage wird jemals blockiert. Denk an eine
Überwachungskamera, nicht an ein Schloss: Es zeigt dir genau, wer deine Routen auskundschaftet, wie
oft und mit welchen Techniken.
> Aus einer Produktions-App extrahiert und mit echtem Traffic praxiserprobt. 335 Tests, keine Laufzeit-
> Abhängigkeiten über Laravel selbst hinaus, und keine Internetverbindung für die Erkennung erforderlich.
>
> Upgrade? Siehe [UPGRADING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/UPGRADING.md). Mitwirken? Siehe [CONTRIBUTING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/CONTRIBUTING.md).
## In unter einer Minute startklar```bash
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate
Dann fügen Sie die Middleware zu Ihrer web-Gruppe hinzu (eine Zeile in bootstrap/app.php bei Laravel 11+,
oder app/Http/Kernel.php bei Laravel 10) — das vollständige Snippet finden Sie unten in Quick Start.
Das war's; die Erkennung ist aktiv.```bash
php artisan threat-detection:doctor # confirms it is actually recording
---
## Wo es einzuordnen ist: IDS vs. WAF vs. Edge
Dieses Paket ist eine **passive IDS auf Anwendungsebene** – es beobachtet und protokolliert, blockiert aber nicht.
Es ist dafür gedacht, *neben* einer WAF oder einem Edge-Dienst zu sitzen, nicht diese zu ersetzen. Jede Ebene sieht
etwas, das die anderen nicht sehen können:
| | **Dieses Paket** (App-IDS) | **WAF** (mod_security, Cloudflare WAF) | **Edge / CDN** (Cloudflare) |
|---|:---:|:---:|:---:|
| Blockiert bösartige Anfragen | ❌ nur Protokollierung | ✅ | ✅ |
| Vollständiger App-Kontext (exakte Route, dekodierte Payload, authentifizierter Benutzer) | ✅ | ⚠️ teilweise | ❌ |
| Integriertes Dashboard + Bedrohungsprotokoll in Ihrer DB | ✅ | ⚠️ variiert | ⚠️ nur Edge |
| App-spezifische Erkennungen (z. B. Aadhaar / PAN / IFSC PII) | ✅ benutzerdefinierte Muster | ❌ | ❌ |
| Funktioniert offline / ohne externen Dienst | ✅ | ⚠️ abhängig | ❌ |
| Stoppt Traffic, bevor er Ihre App erreicht | ❌ | ✅ Edge | ✅ |
| Einrichtung | ein `composer require` | mittel–hoch | niedrig–mittel |
| Kosten | kostenlos, MIT | variiert | kostenlose Stufe + kostenpflichtig |
**Die Kurzfassung:** Eine Edge/WAF ist Ihr Türschloss; dies ist die Überwachungskamera
*im Inneren*, mit dem App-Kontext, um Ihnen genau zu sagen, was auf welcher Route versucht wird, von
wem und wie oft. Nutzen Sie es, um echte Entscheidungen zu treffen – fail2ban-Sperren, Ratenbegrenzungen,
Geo-Blocking – mit Daten, die Ihre Edge-Ebene nie sieht.
### Was es bewusst NICHT ist
- **Keine WAF.** Es blockiert, filtert oder modifiziert niemals eine Anfrage. Verwenden Sie Cloudflare,
mod_security oder eine echte WAF für die Durchsetzung. (Keine Edge-Ebene zum Weiterreichen? Die
[operator-seitigen Helfer](#acting-on-the-data-operator-side-blocking) legen die
Entscheidungen des Pakets offen, sodass Sie Ihre eigene fünfzeilige Blocking-Middleware schreiben können –
der Durchsetzungscode bleibt Ihrer, nicht der des Pakets.)
- **Kein Ersatz für sicheres Programmieren.** Parametrisierte Abfragen, Eingabevalidierung und
Ausgabe-Escaping sind Ihre eigentlichen Verteidigungslinien. Dieses Paket geht davon aus, dass Ihr Code bereits
sicher ist, und gibt Ihnen *Sichtbarkeit*, keinen Schutz.
- **Kein Edge-Dienst.** Wenn Sie Cloudflare davorstellen können, tun Sie das – und fügen Sie dies dann für die
Details auf Anwendungsebene hinzu, die Edge-Dienste nicht sehen können.
### Was machen Sie also tatsächlich damit?
Die häufigste Frage zu einem Detektor, der nie blockiert. Vier Antworten, in
aufsteigender Reihenfolge des Aufwands:
| Sie möchten | Verwenden Sie | Aufwand |
|---|---|---|
| Sehen, was Sie trifft | Das [Dashboard](#dashboard) oder `threat-detection:stats` | keiner, es läuft bereits |
| Wiederholungstäter an der Firewall sperren | [`threat-detection:export-fail2ban`](#artisan-commands) – an einen Cron weiterleiten | eine Zeile |
| Auf Webserver-Ebene verweigern | [`threat-detection:export-blocklist`](#artisan-commands) → nginx/apache-Direktiven | eine Zeile |
| Anfragen in der App ablehnen | [Operator-seitige Helfer](#acting-on-the-data-operator-side-blocking) – `isBlocklisted()`, `isDdosThresholdExceeded()` | ~10 Zeilen eigener Middleware |
| In Echtzeit reagieren | Das [`ThreatDetected`-Event](#threatdetected-event) – Telegram, SIEM, PagerDuty | ein Listener |
Das Paket liefert die Intelligenz; Sie liefern die Ablehnung. Diese Trennung ist
bewusst – Durchsetzungscode, der in Ihrer App lebt, ist Code, den Sie lesen,
testen und abschalten können, und das bedeutet, dass ein Erkennungsfehler Ihre Website niemals lahmlegen kann.
### Wie es im Vergleich zu anderen Laravel-Sicherheitspaketen abschneidet
Diese lösen unterschiedliche Probleme und ergänzen sich gut – die Tabelle dient der Auswahl des
richtigen Werkzeugs, nicht dem Gewinnen.
| Paket | Was es tut | Blockiert? | Verwenden Sie es, wenn |
|---|---|:---:|---|
| **dieses Paket** | Scannt jede Anfrage gegen 150+ Muster, protokolliert mit vollem App-Kontext | ❌ | Sie *sehen* möchten, was gegen Ihre App versucht wird |
| `spatie/laravel-honeypot` | Verstecktes Formularfeld, das Spam-Bots abfängt | ✅ nur Formular | Sie öffentliche Formulare haben, die gespammt werden |
| `graham-campbell/security` | Entfernt XSS-ähnliches Markup aus Eingaben | ✅ mutiert | Sie naive Eingabebereinigung möchten |
| `spatie/laravel-csp` | Sendet Content-Security-Policy-Header | ✅ Browser | Sie einschränken möchten, was der Browser lädt |
| `laravel/fortify` + Ratenbegrenzungen | Auth-Drosselung und Sperrung | ✅ | Sie Brute-Force-Schutz beim Login benötigen |
| Cloudflare / mod_security | Edge-WAF, blockiert vor Ihrer App | ✅ | Sie möchten, dass Traffic gestoppt wird, bevor er ankommt |
Die ehrliche Zusammenfassung: Ein Honeypot fängt Formular-Spam, eine WAF blockiert bekannten schlechten Traffic
an der Edge, und CSP schränkt den Browser ein. **Keines davon sagt Ihnen, was ein
Angreifer gegen Ihre spezifischen Routen versucht hat, mit dekodierter Payload und dem
authentifizierten Benutzer.** Diese Lücke füllt dieses Paket – und deshalb blockiert das
Paket bewusst nicht: Sie können es neben allen oben genannten ausführen,
ohne dass sie sich gegenseitig bekämpfen.
---
## Anforderungen
- PHP 8.2+ (Laravel 13 erfordert PHP 8.3+)
- Laravel 10.x, 11.x, 12.x oder 13.x
- Jede von Laravel unterstützte Datenbank (MySQL, PostgreSQL, SQLite, SQL Server)
- Jeder Cache-Treiber – **kein Redis- oder Queue-Worker erforderlich**. Redis/Memcached wird
nur *empfohlen*, um die optionale DDoS-Prüfung zu aktivieren (die sich bei
nicht-atomaren Treibern automatisch deaktiviert). Queued-Writes sind optional und standardmäßig deaktiviert.
---
## So funktioniert es
1. Eine Middleware scannt jede eingehende HTTP-Anfrage
2. Die Anfrage wird gegen 158 Regex-Muster geprüft, die SQL-Injection, XSS, RCE, Dateitraversal, SSRF, LDAP, XPath, SSTI und mehr abdecken
3. Wenn ein Bedrohungsmuster übereinstimmt, wird ein Datensatz in Ihre `threat_logs`-Datenbanktabelle geschrieben, mit IP, URL, Bedrohungstyp, Schweregrad und einem Konfidenzwert
4. Optional wird eine Slack-Benachrichtigung für Bedrohungen mit hohem Schweregrad gesendet
5. Die Anfrage wird normal fortgesetzt – **es wird nichts blockiert**
Für die Erkennung ist keine Internetverbindung erforderlich.
---
## Schnellstart
### 1. Das Paket installieren```bash
composer require jayanta/laravel-threat-detection
2. Migrationen veröffentlichen und ausführen
Dieser Schritt ist erforderlich. Ohne ihn erkennt das Paket zwar Bedrohungen, kann sie aber nicht in der Datenbank speichern. Wenn Sie diesen Schritt überspringen, existiert Ihre
threat_logs-Tabelle nicht und alle Erkennungen gehen stillschweigend verloren (Sie sehen nur Fehler instorage/logs/laravel.log).```bash php artisan vendor:publish --tag=threat-detection-migrations php artisan migrate
Dies erstellt zwei Tabellen: `threat_logs` (speichert erkannte Bedrohungen) und `threat_exclusion_rules` (speichert Regeln für Fehlalarme).
**Überprüfen, dass die Tabellen erstellt wurden:**```bash
php artisan migrate:status
Suchen Sie nach create_threat_logs_table, add_confidence_to_threat_logs_table und create_threat_exclusion_rules_table – alle sollten Ran anzeigen.
3. Middleware registrieren
Die Middleware ist das, was Anfragen scannt. Sie müssen sie zu Ihrer web-Middleware-Gruppe hinzufügen.
Wenn Sie Laravel 11 oder 12 verwenden – öffnen Sie bootstrap/app.php:```php
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class,
]);
})
> **So überprüfen Sie Ihre Laravel-Version:** Führen Sie `php artisan --version` in Ihrem Terminal aus.
**Wenn Sie Laravel 10 verwenden** – öffnen Sie `app/Http/Kernel.php`:```php
protected $middlewareGroups = [
'web' => [
// ... existing middleware
\JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class,
],
];
4. (Optional) Veröffentlichen Sie die Konfigurationsdatei```bash
php artisan vendor:publish --tag=threat-detection-config
Das Paket funktioniert mit sinnvollen Standardeinstellungen. Durch das Veröffentlichen der Konfiguration kannst du Erkennungsmuster, Sensibilitätsmodi, Slack-Benachrichtigungen und mehr anpassen. Wenn du diesen Schritt überspringst, funktioniert trotzdem alles.
**Das war's.** Deine App erkennt jetzt Bedrohungen.
---
## Überprüfen, dass es funktioniert
Nach der Installation löse eine Testbedrohung aus und bestätige, dass sie protokolliert wurde.
### Schritt 1: Starte deine App```bash
php artisan serve
Schritt 2: Öffnen Sie eine Test-URL in Ihrem Browser
Hängen Sie einen bösartigen Abfrageparameter an eine beliebige vorhandene Route in Ihrer App an (Ihre Startseite, eine Produktseite usw.). Zum Beispiel:
SQL-Injection:``` http://localhost:8000/?q=' UNION SELECT * FROM users--
**XSS (Cross-Site Scripting):**```
http://localhost:8000/?q=<script>alert(1)</script>
Verzeichnis-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
**Windows-Befehlsinjektion:**```
http://localhost:8000/?cmd=powershell -c whoami
DROP TABLE (SQL-DDL):``` http://localhost:8000/?q=DROP TABLE users
> Verwende eine Route, die in deiner App tatsächlich existiert (wie `/`). Wenn die URL einen 404 zurückgibt, wurde die Middleware möglicherweise nicht ausgeführt.
### Schritt 3: Prüfen, ob Bedrohungen protokolliert wurden
**Option A – Artisan-Befehl (am schnellsten):**```bash
php artisan threat-detection:stats
Option B – Tinker:```bash php artisan tinker
```php
DB::table('threat_logs')->latest()->take(5)->get(['ip_address', 'type', 'threat_level', 'confidence_score']);
Option C – Laravel-Protokolldatei:
Jede erkannte Bedrohung wird als Warnung in storage/logs/laravel.log geschrieben:```
[high] Threat Detected: [middleware] SQL Injection UNION from 127.0.0.1 (http://localhost:8000/?q=...) [confidence: 50%]
### Wissenswertes beim Testen
| Verhalten | Erklärung |
|----------|-------------|
| Gleiche Bedrohung wird nur einmal pro 5 Minuten protokolliert | Deduplizierung: gleiche IP + gleicher Bedrohungstyp wird 5 Minuten lang zwischengespeichert. Verwenden Sie für jeden Test **verschiedene Angriffstypen** oder warten Sie zwischen den Tests. |
| `curl`-Anfragen lösen zusätzliche Erkennung aus | Die Verwendung von `curl` protokolliert ebenfalls eine „cURL Command“-User-Agent-Erkennung (niedriger Schweregrad). Das ist zu erwarten – das Paket erkennt automatisierte Tools. |
| Das Paket blockiert niemals Anfragen | Ihre Anwendung funktioniert weiterhin normal. Die Erkennung ist passiv. |
| Keine Slack-Einrichtung erforderlich | Benachrichtigungen sind standardmäßig deaktiviert. |
| Keine Internetverbindung erforderlich | Die Kernerkennung erfolgt zu 100 % lokal. Nur der optionale Befehl `threat-detection:enrich` ruft eine externe API für Geodaten auf. |
### Fehlerbehebung
**Beginnen Sie hier – ein Befehl beantwortet das meiste davon:**```bash
php artisan threat-detection:doctor
Es prüft die Dinge, die eine Erkennung still scheitern lassen – wo das Dashboard leer bleibt, was identisch zu „keine Angriffe“ aussieht – und gibt für jeden Punkt die genaue Lösung aus. Es beendet sich mit einem Fehlercode ungleich Null bei einem echten Fehler, sodass es sicher in CI oder einem Deploy-Schritt ausgeführt werden kann.``` 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.
Was es abdeckt: Erkennung für diese Umgebung aktiviert; jede Spalte, die der
Autor benötigt (eine fehlende verwirft **jede** Bedrohung); Dashboard/API-Spalten; die
Ausschlussregeln-Tabelle; ob die Middleware tatsächlich an eine Route oder
Gruppe angebunden ist; veröffentlichte Konfiguration, die älter als diese Version ist; benutzerdefinierte Muster, die
eingebaute überschatten; einen Cache-Treiber, der kein DDoS-Zählen kann; und ein Dashboard oder
eine API, die ohne Authentifizierung offen gelassen wurde.
**„Ich habe getestet, aber `threat-detection:stats` zeigt null Bedrohungen“ / „Bedrohungen werden nicht in der Datenbank gespeichert“**
Wenn der Doctor bestanden hat, ist die Installation in Ordnung und das Problem liegt an der Testanfrage
selbst. Drei Dinge kann er nicht für dich prüfen:
| Prüfung | So verifizierst du |
|-------|---------------|
| IP ist nicht auf der Whitelist | Wenn du `THREAT_DETECTION_WHITELISTED_IPS` zu `.env` hinzugefügt hast, entferne es während des Tests |
| Eine vorhandene Route verwendet | Die Test-URL muss mit einer echten Route übereinstimmen (z. B. `/`). Ein 404 bedeutet, dass die Middleware nie ausgeführt wurde |
| Dedup-Cache | Gleiche IP + gleicher Angriffstyp wird 5 Minuten lang gecacht – versuche einen anderen Angriffstyp |
> Die alleinige Ausführung von `php artisan migrate` reicht nie aus: Die Migrationsdateien liegen
> im Paket und müssen zuerst in `database/migrations/` deiner App veröffentlicht werden.
> Der Doctor gibt den genauen Befehl aus, wenn dies das Problem ist.
**„API gibt 401 Unauthorized zurück“**
Siehe [API-Authentifizierung](#api-authentication) unten.
**„Dashboard zeigt 404“**
Das Dashboard ist standardmäßig deaktiviert. Füge `THREAT_DETECTION_DASHBOARD=true` zu `.env` hinzu und leere den Routen-Cache:```bash
php artisan route:clear
Funktionen
- 150+ Erkennungsmuster – SQL-Injection (UNION, DDL, DML, Dateioperationen), XSS (Script, SVG, CSS-Ausdruck), RCE, Directory Traversal, SSRF, XXE, Log4Shell, NoSQL-Injection, Command Injection (Linux + Windows), LDAP-Injection, XPath-Injection, SSTI, CRLF-Injection, Java-Deserialisierung und mehr
- 83 Bot-/Scanner-Signaturen – SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker und 70+ weitere Scanner- und Bot-Signaturen
- KI-Scraper-Erkennung – GPTBot, ClaudeBot, ByteSpider, Common Crawl und andere KI-Trainings-Bots
- Headless-Browser-Erkennung – HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright
- 404-Probe-Tracking – Erkennt Aufklärungssonden, die bekannte verwundbare Pfade treffen (
/wp-admin,/.env,/phpmyadmin,/actuatorusw.) mit 50+ Standard-Probe-Pfaden - DDoS-Überwachung – Ratenbasierte Schwellenwerterkennung mit konfigurierbaren Zeitfenstern
- Konfidenz-Bewertung – Jede Bedrohung erhält einen Konfidenzwert von 0–100 basierend auf Musteranzahl, Kontext und Signalen
- Umgehungsresistenz – Normalisierungs-Pipeline vereitelt SQL-Kommentar-Einfügungen, doppelte URL-Kodierung, HTML-Entity-Kodierung, Unicode-Escapes und Hex-Escapes vor dem Musterabgleich
- CVE-Erkennung – Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit-RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
- Kontextbewusste Erkennung – Muster in Query-Strings werden höher bewertet als solche im Request-Body
- Request-Body-Scanning – Sowohl formularcodierte als auch JSON-Request-Bodies (
application/json) werden untersucht - Sichere Felder – Bestimmte Formularfelder vom Scannen ausschließen (für CMS-Editoren, Code-Eingaben, Suchfelder)
- False-Positive-Meldung – Bedrohungen aus dem Dashboard als False Positives markieren; erstellt automatisch Ausschlussregeln
- Drei Erkennungsmodi –
strict,balanced(Standard) undrelaxed– einstellbare Empfindlichkeit - Inhalts-Pfad-Unterdrückung – CMS-/Blog-Pfade auf die Whitelist setzen, um niedrige/mittlere Warnungen aus Rich Content zu unterdrücken
- PII-Erkennung – Muster für die Offenlegung sensibler Daten (pro Region konfigurierbar)
- Geo-Anreicherung – Identifizierung von Land, Stadt, ISP und Cloud-Anbieter über eine kostenlose API
- Slack-Benachrichtigungen – Echtzeit-Benachrichtigungen bei Bedrohungen mit hohem Schweregrad (funktioniert mit Laravel 10 und 11+)
- Integriertes Dashboard – Dark-Mode-Blade-Dashboard (Alpine.js + Tailwind CDN, kein Build-Schritt)
- Dashboard-Auth-Schutz – Konfigurierbare Authentifizierung für Dashboard und API (keine, Auth, Rolle oder IP-basiert)
- 15 API-Endpunkte – Vollständige REST-API für die Erstellung eigener Vue/React/Mobile-Dashboards
- Fail2ban-Export – Export erkannte IPs im fail2ban-kompatiblen Format oder als einfache Blocklist
- Blocklist-Export – Export von IPs im nginx-deny-, Apache-deny-, CSV- oder Klartextformat
- CSV-Export – Bedrohungsprotokoll-Export mit einem Klick (bis zu 10.000 Zeilen)
- Korrelationsanalyse – Erkennung koordinierter Angriffe und Angriffskampagnen über mehrere IPs hinweg
- Leistungsoptimiert – Kategoriebasiertes verzögertes Musterladen (führt Regex nur für relevante Angriffskategorien aus), früher Abbruch bei sauberen Requests, Browser-UA-Kurzschluss (überspringt 70+ Prüfungen für normale Browser), Probe-Pfad-Hash-Lookup, Batch-DB-Inserts, konfigurierbare maximale Erkennungen pro Request
- Datenbankunabhängig – MySQL, PostgreSQL, SQLite, SQL Server
- Null Konfiguration – Funktioniert sofort mit sinnvollen Standardwerten
- Sicher by Design – Die Middleware fängt ihre eigenen Fehler ab. Wenn die Erkennung fehlschlägt, läuft Ihre App weiter. Requests werden niemals blockiert.
Konfiguration
Das Paket funktioniert ohne jegliche .env-Änderungen. Alle untenstehenden Werte sind optional – fügen Sie sie nur hinzu, wenn Sie die Standardwerte überschreiben möchten.```env
Enable/disable detection globally (default: true)
THREAT_DETECTION_ENABLED=true
Detection sensitivity (default: balanced)
Options: strict, balanced, relaxed
THREAT_DETECTION_MODE=balanced
Custom table name (default: threat_logs)
THREAT_DETECTION_TABLE=threat_logs
Your ISO 3166-1 alpha-2 country code (default: IN)
Drives the is_foreign flag on every enriched row — set this or every
non-Indian address is reported as foreign.
THREAT_DETECTION_HOME_COUNTRY=IN
Geo-enrichment provider used by threat-detection:enrich (default shown).
Cleartext HTTP because ip-api.com's free tier rejects HTTPS; point this at
an HTTPS endpoint if you hold a key. Enrichment is opt-in either way.
THREAT_DETECTION_GEO_ENDPOINT=http://ip-api.com/json
Dashboard URL path (default: threat-detection)
THREAT_DETECTION_DASHBOARD_PATH=threat-detection
API route prefix (default: api/threat-detection)
THREAT_DETECTION_API_PREFIX=api/threat-detection
Role required when the API guard is 'role' (default: admin)
THREAT_DETECTION_API_ROLE=admin
Allowed IPs when the API guard is 'ip'. Comma-separated, CIDR supported.
THREAT_DETECTION_API_IPS=127.0.0.1,10.0.0.0/8
Username shown on Slack alerts (default: ThreatBot)
THREAT_DETECTION_SLACK_USERNAME=ThreatBot
Whitelist IPs to skip detection entirely (default: empty)
Supports CIDR notation. Comma-separated.
THREAT_DETECTION_WHITELISTED_IPS=10.0.0.0/8,192.168.1.0/24
Static operator denylist read by ThreatDetection::isBlocklisted() (default: empty)
The package itself never blocks — see "Acting on the Data" for the
enforcement recipe. Supports CIDR. Whitelist wins on overlap.
THREAT_DETECTION_BLOCKLISTED_IPS=203.0.113.0/24,198.51.100.7
DDoS detection thresholds (defaults shown)
THREAT_DETECTION_DDOS_THRESHOLD=300
THREAT_DETECTION_DDOS_WINDOW=60
Minimum confidence score to log a threat (default: 0)
Threats below this score are silently ignored.
THREAT_DETECTION_MIN_CONFIDENCE=0
Slack notifications (disabled by default)
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts
Dashboard (disabled by default)
THREAT_DETECTION_DASHBOARD=true
API endpoints (enabled by default)
THREAT_DETECTION_API=true
API rate limiting (default: 60 requests per minute)
THREAT_DETECTION_API_THROTTLE=60,1
Queue support - offload DB writes to a queue (disabled by default).
OPTIONAL: only enable if your app already runs a queue worker. When false
(default), threats are written synchronously with a plain DB insert - no
Redis, no worker, nothing extra to run.
THREAT_DETECTION_QUEUE=false
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=default
Auto-purge old logs (disabled by default)
Requires Laravel scheduler to be running.
THREAT_DETECTION_RETENTION=false
THREAT_DETECTION_RETENTION_DAYS=90
404 probe tracking (enabled by default)
Detects bots hitting /wp-admin, /.env, /phpmyadmin, etc.
THREAT_DETECTION_PROBE_TRACKING=true
Max detections per request (default: 0 = unlimited)
Stop scanning after N pattern matches per request.
THREAT_DETECTION_MAX_DETECTIONS=0
Dashboard auth guard (default: none)
Options: none, auth, role, ip
THREAT_DETECTION_DASHBOARD_GUARD=none
THREAT_DETECTION_DASHBOARD_ROLE=admin
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1
API auth guard (default: none - uses existing middleware config)
THREAT_DETECTION_API_GUARD=none
### Erkennungsmodi
| Modus | Konfidenzschwelle | Verhalten |
|------|---------------------|----------|
| `strict` | 0 (protokolliert alles) | Alle Muster aktiv, niedrigste Schwellenwerte. Erfasst alles, kann aber legitimen Datenverkehr markieren. |
| `balanced` | 10 | Standard. Konfidenzbewertung aktiv, Standard-Schwellenwerte. Gut für die meisten Apps. |
| `relaxed` | 40 | Nur Muster mit hoher Schwere lösen aus. Am besten für inhaltslastige Websites mit häufigen Fehlalarmen. |
### Aktivierte Umgebungen
Standardmäßig läuft die Erkennung in `production`, `staging` und `local`. Um dies zu ändern, veröffentlichen Sie die Konfiguration und bearbeiten Sie:```php
'enabled_environments' => ['production', 'staging', 'local'],
Um die Erkennung in Ihrer Testsuite zu deaktivieren, setzen Sie APP_ENV=testing (nicht in der obigen Liste) oder fügen Sie Folgendes zu Ihrer phpunit.xml hinzu:```xml
### Config-Referenz
Veröffentlichen Sie die Konfigurationsdatei, um alle verfügbaren Optionen zu sehen:```bash
php artisan vendor:publish --tag=threat-detection-config
Wichtige Konfigurationsabschnitte: skip_paths (zu überspringende Pfade), only_paths (Whitelist-Modus), auth_paths (intelligente Erkennung von Login-Routen), content_paths (niedrige Alarme unterdrücken), safe_fields (bestimmte Felder vom Scannen ausschließen), safe_paths (pfadbewusste Feldausschlüsse für verschachteltes JSON), probe_tracking (404-Probe-Erkennung), context_weights (Bewertungsmultiplikatoren), threat_levels (Zuordnung von Schweregrad-Schlüsselwörtern), api_route_filtering (niedrige/mittlere Alarme auf API-Routen unterdrücken), queue (asynchrone Verarbeitung), retention (automatische Bereinigung), max_detections_per_request (Leistungsgrenze), dashboard.guard / api.guard (Authentifizierungsmodus).
Routen-Whitelist (only_paths)
Wenn Ihre App viele Routen hat, Sie sich aber nur für einige wenige interessieren, verwenden Sie only_paths, um nur diese Routen zu scannen. Alle anderen Routen werden automatisch übersprungen – keinerlei Middleware-Overhead.```php
// config/threat-detection.php
'only_paths' => [
'admin/',
'api/',
'login',
'register',
],
Leer lassen (Standard), um alle Routen zu scannen (abhängig von `skip_paths`). Wenn beide konfiguriert sind, wird zuerst `only_paths` geprüft, dann gilt `skip_paths` innerhalb der übereinstimmenden Menge.
### Warteschlangenunterstützung
Standardmäßig erfolgt die Bedrohungsprotokollierung synchron im Anforderungszyklus. Für Anwendungen mit hohem Datenverkehr können Sie DB-Schreibvorgänge und Slack-Benachrichtigungen an eine Warteschlange auslagern:```env
THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=threat-logs
Dieser Vorgang löst einen StoreThreatLog-Job aus (3 Wiederholungen, Backoff 10s/30s). Die Erkennung erfolgt weiterhin in Echtzeit – nur das Schreiben wird verzögert.
Auto-Bereinigung (Aufbewahrungsrichtlinie)
Löscht automatisch alte Bedrohungsprotokolle nach einem täglichen Zeitplan:```env THREAT_DETECTION_RETENTION=true THREAT_DETECTION_RETENTION_DAYS=90
Erfordert, dass der Scheduler von Laravel ausgeführt wird (`php artisan schedule:run`). Läuft täglich um 02:00 Uhr über `threat-detection:purge`.
### ThreatDetected-Ereignis
Jede bestätigte Bedrohung löst ein `ThreatDetected`-Ereignis aus, auf das Sie hören können:```php
// app/Providers/EventServiceProvider.php
use JayAnta\ThreatDetection\Events\ThreatDetected;
protected $listen = [
ThreatDetected::class => [
YourCustomListener::class,
],
];
Das Ereignis trägt $threatLog (vollständiges DB-Zeilen-Array), $ipAddress und $threatLevel. Verwenden Sie es, um benutzerdefinierte Aktionen auszulösen – Telegram-Benachrichtigungen senden, eine Blocklist aktualisieren, einen SIEM füttern usw.
DdosThresholdExceeded-Ereignis
Wenn ein Client die konfigurierte DDoS-Schwelle (ddos.threshold Anfragen innerhalb von
ddos.window Sekunden) überschreitet, wird ein DdosThresholdExceeded-Ereignis zusammen mit dem
Bedrohungsprotokolleintrag ausgelöst:```php
use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;
protected $listen = [ DdosThresholdExceeded::class => [ YourFloodListener::class, ], ];
Das Ereignis trägt `$ipAddress`, `$requestCount`, `$threshold` und `$windowSeconds`. Es wird
auf einmal pro IP pro Dedup-Fenster gedrosselt (gleiche Drosselung wie bei der Log-Zeile), sodass eine Flut
deine Listener nicht überwältigen kann. Verwende es für Warnungen oder um einen externen Bann-Speicher zu speisen; um
über dem Schwellenwert liegende Clients zu *verweigern*, verwende stattdessen `ThreatDetection::isDdosThresholdExceeded($ip)` aus deiner eigenen
Middleware — siehe [Handeln auf Basis der Daten](#acting-on-the-data-operator-side-blocking).
---
## Slack-Benachrichtigungen
Slack-Warnungen sind standardmäßig deaktiviert. Zum Aktivieren:```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts
Nur Bedrohungen mit hohem Schweregrad lösen standardmäßig Benachrichtigungen aus (konfigurierbar über notify_levels in der Konfiguration).
Laravel 10: Verwendet die integrierte SlackMessage-Benachrichtigungsklasse. Kein zusätzliches Paket erforderlich.
Laravel 11+: Der integrierte Slack-Kanal wurde entfernt. Das Paket erkennt dies automatisch und sendet rohe HTTP-POST-Webhooks an Ihre Slack-URL. Kein zusätzliches Paket erforderlich. Wenn Sie den vollständigen Benachrichtigungskanal bevorzugen, installieren Sie:```bash composer require laravel/slack-notification-channel
---
## Dashboard
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/12500/fc7950bd0cc6323bcc2d62b03e31c99edc7450b0ef76f9cbfa5133b527b25269.png" alt="Threat Detection Dashboard — Statistiken, 7-Tage-Zeitverlauf, Live-Bedrohungsprotokoll, häufigste angreifende IPs und Bedrohungen nach Land" width="100%">
</p>
Das Paket wird mit einem integrierten Dark-Mode-Dashboard geliefert (Alpine.js + Tailwind CDN – kein Build-Schritt erforderlich).```
+-------------------------------------------------------------------------+
| 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 |
+-------------------------------------------------------------------------+
Dashboard aktivieren
Füge zu .env hinzu:```env
THREAT_DETECTION_DASHBOARD=true
Besuchen Sie: `http://your-app.test/threat-detection`
### Zugang während der lokalen Entwicklung
Das Dashboard verwendet standardmäßig die Middleware `['web', 'auth']`, sodass Benutzer angemeldet sein müssen. Wenn Ihre Anwendung noch keine Authentifizierung hat, beschränken Sie sie stattdessen auf Ihren eigenen Rechner:```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1
Alle Guard-Optionen sowie der separate Guard auf den Endpunkten, der Erkennungen deaktiviert, werden in Dashboard- und API-Authentifizierung behandelt.
Wenn das Dashboard leere Daten anzeigt, wurde die Seite geladen, aber ihre API-Aufrufe wurden nicht ausgeführt. Siehe API-Authentifizierung.
API-Endpunkte
Das Paket stellt 15 REST-Endpunkte für den Aufbau eigener Dashboards oder Integrationen bereit.
API-Authentifizierung
API-Routen verwenden standardmäßig die Middleware auth:sanctum. Das Paket behandelt dies elegant:
- Sanctum installiert: Die API erfordert eine Authentifizierung über Sanctum-Tokens oder SPA-Sitzungsauthentifizierung.
- Sanctum NICHT installiert: Das Paket erkennt automatisch, dass Sanctum fehlt, und fällt nur auf
['api']zurück. Die API funktioniert ohne Authentifizierung.
Wenn Sie Sanctum nicht verwenden, Ihre API aber schützen möchten, haben Sie zwei Optionen:
Option 1 – Den integrierten Auth-Guard verwenden:```env THREAT_DETECTION_API_GUARD=auth
**Option 2 – Ändern Sie die Middleware direkt:**```php
// config/threat-detection.php
'api' => [
'enabled' => true,
'prefix' => 'api/threat-detection',
'middleware' => ['api', 'auth'], // or 'auth:your-guard'
],
Für lokale Tests (falls Sanctum den Zugriff blockiert), ändere vorübergehend:```php 'middleware' => ['api'], // remove 'auth:sanctum'
> Stellen Sie die Authentifizierung wieder her, bevor Sie in die Produktion bereitstellen.
### Endpunkt-Referenz
| Methode | Endpunkt | Beschreibung |
|---------|----------|--------------|
| GET | `/api/threat-detection/threats` | Bedrohungen auflisten (paginiert, filterbar) |
| GET | `/api/threat-detection/threats/{id}` | Details einer einzelnen Bedrohung |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Bedrohung als Fehlalarm markieren |
| GET | `/api/threat-detection/stats` | Gesamtstatistiken |
| GET | `/api/threat-detection/summary` | Detaillierte Aufschlüsselung nach Typ, Stufe, IP |
| GET | `/api/threat-detection/live-count` | Bedrohungen in der letzten Stunde |
| GET | `/api/threat-detection/by-country` | Nach Land gruppiert |
| GET | `/api/threat-detection/by-cloud-provider` | Nach Cloud-Anbieter gruppiert |
| GET | `/api/threat-detection/top-ips` | Hauptverursachende IPs |
| GET | `/api/threat-detection/timeline` | Bedrohungs-Zeitverlauf (für Diagramme) |
| GET | `/api/threat-detection/ip-stats?ip=x.x.x.x` | Statistiken für eine bestimmte IP |
| GET | `/api/threat-detection/correlation` | Korrelationsanalyse |
| GET | `/api/threat-detection/export` | Als CSV exportieren |
| GET | `/api/threat-detection/exclusion-rules` | Ausschlussregeln auflisten |
| DELETE | `/api/threat-detection/exclusion-rules/{id}` | Eine Ausschlussregel löschen |
### Abfrageparameter für `/threats`
| Parameter | Beschreibung |
|-----------|--------------|
| `keyword` | Suche in IP, URL, Typ |
| `ip` | Nach IP-Adresse filtern |
| `level` | Nach Bedrohungsstufe filtern (`high`, `medium`, `low`) |
| `type` | Nach Bedrohungstyp filtern |
| `country` | Nach Ländercode filtern |
| `is_foreign` | Ausländische IPs filtern (`true`/`false`) |
| `cloud_provider` | Nach Cloud-Anbieter filtern |
| `is_false_positive` | Nach Fehlalarm-Status filtern (`true`/`false`) |
| `date_from` / `date_to` | Datumsbereichsfilter |
| `per_page` | Einträge pro Seite (Standard: 20, max: 100) |
### Beispiel einer API-Antwort
**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
}
}
Erstellen benutzerdefinierter Frontends
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));
}, []);
Wenn Ihre API
auth:sanctumverwendet, fügen Sie Authentifizierungs-Header hinzu oder konfigurieren Sie die Sanctum-SPA-Authentifizierung für cookie-basierte Anfragen.
Artisan-Befehle```bash
Check that detection is installed, wired up and actually recording.
Exits non-zero on a real failure, so it works in CI or a deploy step.
php artisan threat-detection:doctor
View threat stats summary in the terminal
php artisan threat-detection:stats
Enrich existing logs with geo-data (country, city, ISP, cloud provider)
Uses the free ip-api.com service (rate-limited to 45 req/min, auto-throttled)
php artisan threat-detection:enrich --days=7
Purge old logs to keep the database clean
php artisan threat-detection:purge --days=30
Export threat IPs for fail2ban (pipe to file or run directly)
php artisan threat-detection:export-fail2ban --level=high --since=24h --min-hits=5 php artisan threat-detection:export-fail2ban --format=plain > /tmp/banlist.txt
Export blocklist in various formats
php artisan threat-detection:export-blocklist --format=nginx > /etc/nginx/blocklist.conf php artisan threat-detection:export-blocklist --format=apache > .htaccess-deny php artisan threat-detection:export-blocklist --format=csv --since=7d
---
## Reagieren auf die Daten (Blockierung auf Betreiberseite)
Das Paket blockiert niemals eine Anfrage – das ist seine Identität, kein Standard. Die obigen
Exporte speisen Durchsetzungsebenen, die Sie bereits betreiben (fail2ban, nginx, eine Edge-WAF). Aber einige Bereitstellungen
haben keine solche Ebene, die gespeist werden könnte – Shared Hosting, PaaS, Container hinter einem Load Balancer, den Sie
nicht kontrollieren. Für diese stellt das Paket seine *Entscheidungen* als Helfer bereit, und Sie schreiben die
Durchsetzungs-Middleware selbst. Gleiche Architektur wie die Exporte: **Wir liefern die
Intelligenz, Sie liefern die Verweigerung.**```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);
}
}
Bevor du auf IP-Ebene durchsetzt, konfiguriere
TrustProxies.Alles oben hängt von
$request->ip()ab. Hinter einem Load Balancer, CDN oder Reverse Proxy gibt das die Client-IP nur dann zurück, wenn Laravel mitgeteilt wird, welchen Proxys vertraut werden soll. Ist das nicht der Fall, brechen zwei Dinge gleichzeitig: Jede Anfrage scheint vom Proxy zu kommen, sodass ein Denylist-Eintrag entweder den gesamten Traffic blockiert oder gar keinen — und schlimmer noch: Wenn die App einem weitergeleiteten Header vertraut, dem sie nicht vertrauen sollte, setzt ein AngreiferX-Forwarded-Forund umgeht die Blocklist direkt.Das ist hier wichtiger als bei
whitelisted_ips. Ein falscher Whitelist-Treffer bedeutet nur, dass das Paket eine Anfrage scannt, die es übersprungen hätte: Es versagt sicher. Eine Denylist, die zur Verweigerung von Traffic verwendet wird, versagt offen — du glaubst, eine Adresse sei blockiert, obwohl sie es nicht ist. Prüfeapp/Http/Middleware/TrustProxies.php(oder dentrustProxies-Aufruf inbootstrap/app.phpbei Laravel 11+), bevor du dich bei der Durchsetzung auf einen der beiden Helfer verlässt.
Registriere es global (vor der Erkennungs-Middleware ist in Ordnung — die Helfer lesen Konfiguration und Cache, sie hängen nicht von der Middleware-Reihenfolge ab):```php // bootstrap/app.php (Laravel 11+) ->withMiddleware(function ($middleware) { $middleware->prepend(\App\Http\Middleware\EnforceThreatDecisions::class); })
Die Helfer:
| Helfer | Rückgabe | Unterstützt durch |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | `blocklisted_ips`-Konfiguration (CIDR über `IpUtils`; Whitelist gewinnt) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | `whitelisted_ips`-Konfiguration |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | den Flood-Zähler, den die Erkennungs-Middleware verwaltet |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | diesen Zähler im Vergleich zu `ddos.threshold` |
Hinweise:
- **Die Denylist ist statisch und wird vom Betreiber gepflegt.** Nichts im Paket fügt ihr jemals
etwas hinzu — sie führt dieselbe Entscheidung aus, die ein fail2ban-Jail treffen würde („Ich habe das Dashboard gelesen; dieses /24
ist feindselig"), nur innerhalb der App.
- Der DDoS-Zähler zählt nur Anfragen, die die Erkennung erreicht haben (`skip_paths`, whitelisted
IPs und deaktivierte Umgebungen werden nie gezählt) und bleibt bei Cache-Treibern, bei denen die
DDoS-Erkennung deaktiviert ist (`file`, `database`, `null`), bei 0.
- Wenn ein Client den Schwellenwert überschreitet, wird zusätzlich ein [`DdosThresholdExceeded`-Ereignis](#ddosthresholdexceeded-event)
ausgelöst — nützlich für Alarmierung oder die Speisung einer externen Bannliste. Rufe jedoch kein `abort()`
aus dem Listener auf: Listener laufen innerhalb des fail-open
`try/catch` der Erkennungs-Middleware, daher gehört die Verweigerung wie oben in deine eigene Middleware.
---
## 404-Probe-Verfolgung
Das Paket erkennt Aufklärungs-Probes — Bots, die bekannte verwundbare Pfade wie `/wp-admin`, `/.env` oder `/phpmyadmin` auf deiner Nicht-WordPress-, Nicht-phpMyAdmin-Seite ansteuern. Diese haben keine bösartige Nutzlast; der Pfad selbst ist das Signal.
Protokolliert mit einem `[probe]`-Typtag, getrennt von der nutzlastbasierten Erkennung. Wenn eine Probe-Anfrage auch eine bösartige Nutzlast enthält, werden beide unabhängig voneinander protokolliert.
Standardmäßig mit über 50 Probe-Pfaden aktiviert. Anpassbar 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...
],
],
Disable mit THREAT_DETECTION_PROBE_TRACKING=false.
Sichere Felder (Reduzierung falsch positiver Ergebnisse)
Wenn bestimmte Formularfelder legitimerweise HTML, SQL-Schlüsselwörter oder Code enthalten (z. B. CMS-Editoren, Eingaben für Code-Snippets), können Sie diese von der Überprüfung ausschließen:```php // config/threat-detection.php 'safe_fields' => ['content', 'body', 'html', 'description', 'code'],
Hier sind die hier aufgeführten Felder aus den Query-Parametern und dem Request-Body entfernt – sowohl formularcodiert als auch JSON (`application/json`) – bevor die Erkennung ausgeführt wird. Andere Felder in derselben Anfrage werden weiterhin vollständig gescannt.
### Sichere Pfade (pfadbewusst, für verschachtelte JSON-APIs)
`safe_fields` gleicht einen Schlüsselnamen **überall** ab, wo er vorkommt. Für verschachtelte JSON-APIs ist das oft zu weit gefasst – Sie möchten möglicherweise nur den Wert eines bestimmten Felds ausnehmen, ohne diesen Schlüssel überall auszunehmen. Verwenden Sie `safe_paths`, das über die Punktnotation **Pfade** abgleicht und `fnmatch`-Wildcards unterstützt:```php
// config/threat-detection.php
'safe_paths' => ['search.query', 'filters.*.value'],
For example, search.query schließt den Wert von {"search": {"query": "..."}} aus (ein Suchfeld, dessen Text legitimerweise Wörter wie SELECT enthält), während ein query-Feld an anderer Stelle in der Anfrage weiterhin gescannt wird. Alles, was nicht aufgeführt ist, wird genau wie zuvor gescannt.
Post-Match-Validatoren (Prüfsummenbewusste Reduzierung falsch positiver Ergebnisse)
Ein Regex allein kann nicht jede Einschränkung ausdrücken: jede 12-stellige Zahlenfolge entspricht dem Aadhaar-Muster, aber eine echte Aadhaar-Nummer besteht auch die Verhoeff-Prüfsumme. Ordnen Sie eine Musterbezeichnung (Standard oder benutzerdefiniert) einem benannten Validator zu, und ein Regex-Treffer zählt nur dann als Erkennung, wenn mindestens ein übereinstimmender Wert ihn besteht:```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],
Verfügbare Validatoren:
| Validator | Prüfsumme | Typische Verwendung |
|------------|----------|-------------|
| `verhoeff` | Verhoeff | Aadhaar-Nummern |
| `luhn` | Luhn | Kredit-/Debitkartennummern |
Mit der mitgelieferten Zuordnung werden Zeitstempel, Bestell-IDs und Barcodes, die zufällig 12 Ziffern lang sind, nicht mehr als personenbezogene Daten (PII) protokolliert — während echte Aadhaar-Nummern weiterhin erkannt werden. Wenn mehrere Werte übereinstimmen und nur einer die Prüfsumme besteht, wird die Erkennung dennoch ausgelöst: Eine echte Nummer im Rauschen ist immer noch ein Leck.
Kombinieren Sie einen Validator mit Ihrem eigenen Muster für eine prüfsummengesteuerte Kartenerkennung:```php
'custom_patterns' => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],
Ein unbekannter Validatorname schlägt offen fehl — der Treffer wird unvalidiert gezählt und eine Warnung wird einmalig protokolliert — sodass ein Tippfehler niemals stillschweigend ein Erkennungsmuster deaktivieren kann. Vor dieser Funktion veröffentlichte Konfigurationen haben den Schlüssel einfach nicht und behalten ihr exaktes aktuelles Verhalten bei.
Redaktion (Erkennen ist nicht Speichern)
Das Erkennen sensibler Daten bedeutete früher, sie zu speichern. Ein Profilformular mit einer Mobilnummer, PAN und Bankkonto würde drei PII-Muster auslösen, und jede der drei geschriebenen Zeilen behielt den gesamten Request-Body wörtlich bei — für die gesamte Aufbewahrungsdauer gespeichert, lesbar für jeden mit Dashboard- oder Datenbankzugriff. Ein Wert in einer Query-String landete ebenfalls in der url-Spalte. Der Detektor wurde zu einer zweiten, konzentrierten Kopie genau dessen, wovor er warnt.
Standardmäßig aktiv seit v1.7.0. Wenn ein Muster, dessen Label aufgelistet ist, auslöst, wird der von ihm gefundene Wert im gespeicherten Payload und in der URL maskiert:``` BODY: {"name":"Jane Doe","mobile":"[REDACTED]","pan":"[REDACTED]","bank_account":"[REDACTED]"}
Die Warnung, der Endpunkt, die Feldnamen und die angreifende IP bleiben erhalten – nur der Wert wird entfernt. Die Schwärzung erfolgt *nach* der Erkennung, sodass nichts übersehen wird.```php
// config/threat-detection.php
'redact' => [
'enabled' => env('THREAT_DETECTION_REDACT', true),
'mask' => '[REDACTED]',
'labels' => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],
Attack-Payloads werden absichtlich unverändert gelassen – eine Injection-Zeichenkette ist ein Beweisstück, kein Geheimnis, und das Maskieren würde die Untersuchung zerstören. Nur die von dir aufgeführten Labels werden verändert.
Dies ersetzt nicht Safe Fields. Diese verhindern, dass ein Feld gescannt wird; Redaktion ermöglicht es dir, weiter zu scannen und das Speichern zu stoppen. Setze
THREAT_DETECTION_REDACT=false, wenn du vollständige Payloads für forensische Zwecke benötigst.
Dashboard- und API-Authentifizierung
Das Dashboard und die API unterstützen konfigurierbare Auth-Guards über .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
Die gleichen Optionen sind für API-Routen mit `THREAT_DETECTION_API_GUARD` verfügbar.
Wenn `guard=none` (Standard) gesetzt ist, protokolliert das Paket einmal pro Tag eine Warnung, um Sie daran zu erinnern, die Authentifizierung zu konfigurieren.
Die Guard **schließt sicher ab**: Ein nicht erkannter Guard-Wert (z. B. ein Tippfehler) wird mit einem 403 und einer protokollierten Warnung verweigert, anstatt stillschweigend Zugriff zu gewähren, und `guard=role` verweigert (mit einer Warnung) den Zugriff, wenn das authentifizierte Benutzermodell keine `hasRole()`-Methode besitzt.
### Das Deaktivieren einer Erkennung erfordert mehr als nur Lesezugriff
Das Markieren einer Bedrohung als Fehlalarm und das Löschen einer Ausschlussregel unterdrücken beide einen Erkennungstyp für alle – eine andere Berechtigung als das Lesen des Protokolls. Diese beiden Endpunkte werden gegen eine separate Guard geprüft:```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role
Es gilt nur für diese Routen, sodass sich Lesen und Dashboard genau so verhalten, wie es THREAT_DETECTION_API_GUARD vorgibt. Ohne diese Einstellung könnte jeder authentifizierte Benutzer Ihrer Anwendung eine Erkennung deaktivieren.
Wenn Ihr Benutzermodell keine hasRole()-Methode hat, verwenden Sie =auth. Um das Verhalten vor 1.7.0 wiederherzustellen, bei dem jeder authentifizierte Benutzer Erkennungen deaktivieren konnte, verwenden Sie =none – threat-detection:doctor wird eine Warnung ausgeben, solange diese Einstellung aktiv ist.
Hinweis Dashboard ↔ API: Das integrierte Dashboard bezieht seine Daten über die API-Routen mithilfe des Browser-Session-Cookies. Wenn Ihre API-Routen mit
auth:sanctumgeschützt sind, konfigurieren Sie die Sanctum-Stateful-/SPA-Authentifizierung (oder richten Sie das Dashboard auf eine cookie-authentifizierte Guard aus), damit diese AJAX-Aufrufe autorisiert werden – andernfalls wird das Dashboard leer angezeigt.
Benutzerdefinierte Muster
Fügen Sie Ihre eigenen Erkennungs-Regex-Muster in config/threat-detection.php hinzu:```php
'custom_patterns' => [
'/your-regex-here/i' => 'Your Threat Label',
],
**Beispiel – Erkennung einer Sondierung eines benutzerdefinierten Admin-Endpunkts:**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',
Array-Form (Optionen pro Muster)
Neben der klassischen String-Form kann der Wert eines Musters ein Array sein, um die volle Kontrolle zu erhalten:```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`** setzt die Bedrohungsstufe direkt fest, anstatt sie aus den `threat_levels`-Schlüsselwörtern im Label abzuleiten.
- **`contexts`** schränkt das Scannen auf bestimmte Anfrageabschnitte ein – z. B. stoppt ein Kartenmuster, das nur im Body sinnvoll ist, das Abgleichen von Ziffernfolgen in Headern.
- **`validator`** benennt eine Inline-Prüfung nach dem Treffer (siehe [Post-Match-Validatoren](#post-match-validators-checksum-aware-false-positive-reduction)); sie hat Vorrang vor der `pattern_validators`-Label-Zuordnung.
String- und Array-Einträge mischen sich frei in derselben Konfiguration. Fehlerhafte Optionen **schlagen offen fehl** – das Muster scannt weiterhin uneingeschränkt, und eine Warnung wird protokolliert –, sodass ein Konfigurationsfehler eine Erkennung niemals stillschweigend deaktivieren oder einschränken kann.
> **Hinweis:** Häufige Probe-Pfade wie `/wp-login.php`, `/.env`, `/phpmyadmin` werden jetzt automatisch von der Funktion [404-Probe-Verfolgung](#404-probe-tracking) behandelt. Dafür sind keine benutzerdefinierten Muster erforderlich.
Die Bedrohungsstufe für jedes Muster wird automatisch bestimmt, indem Schlüsselwörter im Label gegen die `threat_levels`-Konfiguration abgeglichen werden:```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'],
],
Wenn das Label mit keinem Schlüsselwort übereinstimmt, wird die Bedrohung standardmäßig als low-Schweregrad eingestuft.
Ungültige Regex-Muster werden automatisch übersprungen und als Warnungen protokolliert – sie lassen Ihre Anwendung nicht abstürzen.
Verwendung der Fassade
Für den programmatischen Zugriff auf Bedrohungsdaten außerhalb der 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');
---
## Übergang in die Produktion
Das Paket ist von Natur aus passiv – es blockiert, lehnt oder verändert niemals eine Anfrage, und die Erkennungs-Middleware umschließt ihren gesamten Körper mit `try/catch`, sodass ein Erkennungsfehler Ihre App niemals zum Absturz bringen kann. Es wird mit sinnvollen Standardeinstellungen ausgeliefert und benötigt keine externen Dienste zum Ausführen. Bevor Sie live gehen, ist diese kurze Checkliste einen Blick wert:
1. **Schützen Sie das Dashboard und die API.** Beide verwenden standardmäßig `guard = none` für einen Erststart ohne Konfiguration und protokollieren eine tägliche Warnung, solange sie ungeschützt sind. Setzen Sie vor der Produktion eine Guard – `THREAT_DETECTION_DASHBOARD_GUARD` und `THREAT_DETECTION_API_GUARD` (`auth`, `role` oder `ip`). Ein nicht erkannter Wert oder eine `role`-Guard bei einem Benutzermodell ohne `hasRole()` schlägt jetzt **fail-closed** (403) fehl, sodass ein Tippfehler keine Daten stillschweigend offenlegt. Das Deaktivieren einer Erkennung wird separat durch `THREAT_DETECTION_API_WRITE_GUARD` gesteuert, das standardmäßig `role` verwendet. Siehe [Dashboard- und API-Authentifizierung](#dashboard-and-api-authentication).
2. **Führen Sie die Migrationen aus** (`vendor:publish --tag=threat-detection-migrations && migrate`). Das erneute Veröffentlichen ist sicher – bereits veröffentlichte Migrationen werden übersprungen.
3. **Wählen Sie einen Erkennungsmodus.** `balanced` (Standard) passt für die meisten Apps; verwenden Sie `relaxed` für inhaltslastige Websites, `strict` für sicherheitskritische Oberflächen. Optimieren Sie mit `content_paths`, `safe_fields` und `min_confidence` – siehe [Reduzierung falsch positiver Ergebnisse](#reducing-false-positives).
4. **Überprüfen Sie die regionalen PII-/benutzerdefinierten Muster.** Die Standardeinstellungen sind Indien-zentriert (Aadhaar, PAN, IFSC), und die breiten numerischen Muster (z. B. Bankkonto) können lange numerische IDs außerhalb von Auth-Routen abgleichen. Ersetzen oder kürzen Sie `custom_patterns` für Ihre Region und App, und fügen Sie inhaltslastige Routen zu `auth_paths` / `content_paths` hinzu.
5. **Aktivieren Sie die Aufbewahrung**, wenn Sie Volumen erwarten: `THREAT_DETECTION_RETENTION=true` (automatische Bereinigung über den Scheduler). Erfordert Laravels Scheduler (`schedule:run`), der per Cron ausgeführt wird.
6. **Optionale Extras, alle standardmäßig deaktiviert:** Slack-Benachrichtigungen (`THREAT_DETECTION_NOTIFICATIONS`), Geo-Anreicherung (`php artisan threat-detection:enrich` – die einzige Funktion, die einen ausgehenden Anruf an das kostenlose ip-api.com tätigt), und in die Warteschlange gestellte Schreibvorgänge (`THREAT_DETECTION_QUEUE` – nur aktivieren, wenn Sie bereits einen Queue-Worker ausführen; andernfalls sind Schreibvorgänge synchron und benötigen kein Redis).
Für die Kernerkennung und -protokollierung sind kein Redis, kein Queue-Worker und keine ausgehenden Netzwerkaufrufe erforderlich.
---
## Reduzierung falsch positiver Ergebnisse
Das Paket bietet mehrere Werkzeuge zur Reduzierung falsch positiver Ergebnisse. Verwenden Sie, was zu Ihrer Situation passt:
### Sichere Felder und sichere Pfade
Schließen Sie ein Feld vollständig von der Überprüfung aus, entweder überall nach Namen (`safe_fields`) oder über Punktnotation für verschachteltes JSON (`safe_paths`). Der einfachste Ansatz und der direkteste – das Feld wird übersprungen, sodass darauf keine Erkennung ausgeführt wird.
Vollständige Details und Beispiele: [Sichere Felder](#safe-fields-false-positive-reduction).
### Unterdrückung von Inhalts-Pfaden
Wenn Sie CMS-Editoren, Blog-Post-Formulare oder Kommentarbereiche haben, in denen Benutzer umfangreiche Inhalte einreichen, lösen diese Pfade oft falsch positive Ergebnisse aus (z. B. ein Blog-Post mit `<script>`-Codebeispielen). Fügen Sie diese Pfade hinzu, um niedrige/mittlere Warnungen zu unterdrücken:```php
// config/threat-detection.php
'content_paths' => [
'admin/posts/*',
'admin/pages/*',
'blog/*/edit',
'comments',
],
Auf diesen Pfaden werden nur hochkritische Bedrohungen protokolliert.
Meldung falsch positiver Ergebnisse
Klicken Sie auf die Schaltfläche FP bei einer beliebigen Bedrohung im Dashboard, um sie als falsch positiv zu markieren. Dadurch wird:
- Die Bedrohung als
is_false_positive = truegekennzeichnet - Automatisch eine Ausschlussregel erstellt, sodass ähnliche Bedrohungen von derselben URL/demselben Typ künftig unterdrückt werden
Verwalten Sie Ausschlussregeln über die API:```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}
### Konfidenz-Scoring
Jede Bedrohung erhält einen Konfidenz-Score (0-100), basierend auf:
- Anzahl der Pattern-Übereinstimmungen in derselben Anfrage
- Schweregrad des übereinstimmenden Patterns
- Wo das Pattern gefunden wurde (Query-String > Header > Body)
- Ob der User-Agent mit einem bekannten Angriffstool übereinstimmt
- Aktueller Erkennungsmodus
Bedrohungen unterhalb der Konfidenzschwelle für Ihren Erkennungsmodus werden nicht protokolliert (siehe [Erkennungsmodi](#detection-modes)).
---
## Erkannte Angriffstypen
| Kategorie | Beispiele |
|----------|---------|
| **SQL-Injection** | UNION, boolean, time-based, CHAR-Encoding, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), Dateioperationen (INTO OUTFILE, LOAD_FILE), ORDER-BY-Enumeration, Hex-Strings, UNHEX |
| **NoSQL-Injection** | MongoDB $ne, $gt, $regex, $where-Operatoren |
| **XSS** | Script-Tags, SVG-Event-Handler (`<svg onload=`), HTML-Event-Handler (`<body onload=`, `<img onerror=`), CSS-Ausdrücke, JavaScript-URIs, DOM-Manipulation |
| **Code-Ausführung** | RCE-Shell-Funktionen, PHP-Deserialisierung, Java-Deserialisierung (base64 + Hex-Magic-Bytes), Template-Injection (Blade, JSP, ASP, Jinja2, Velocity), eval(), base64-Decode, PHP assert(), create_function(), preg_replace /e |
| **SSTI** | Mathematische Sonden (`{{7*7}}`), Jinja2-Import/Config, Velocity-Templates, Expression Language |
| **Befehlsinjektion** | Linux (Shell-Funktionen, Befehlsketten, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Dateizugriff** | Directory-Traversal, LFI/RFI-Protokolle, Sonden auf sensible Dateien (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), AWS/GCP-Metadaten, private IPs, hex/dezimal kodierter Localhost, DNS-Rebinding (xip.io, nip.io, sslip.io) |
| **LDAP-Injection** | LDAP-Filter-Manipulation, OR-Injection |
| **XPath-Injection** | Attribut-Selektoren, XPath-Funktionen (contains, substring) |
| **CRLF / Header-Injection** | URL-kodiertes CRLF (`%0d%0a`), LF-Injection, Null-Byte-Injection |
| **Protokollangriffe** | HTTP-Request-Smuggling (CL+TE), SSI-Injection |
| **CVE-Exploits** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit-RCE (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Proben-Tracking** | WordPress (`/wp-admin`, `/wp-login.php`), Konfigurationsdateien (`/.env`, `/.git`), Datenbanktools (`/phpmyadmin`), Technologie-Sonden (`.asp`, `.jsp`), Spring-Actuator, Swagger/API-Dokumentation - 50+ Pfade |
| **Scanner** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei und 20+ weitere (insgesamt 53) |
| **KI-Scraper** | GPTBot, ClaudeBot, ChatGPT, ByteSpider, Cohere, Common Crawl |
| **Headless-Browser** | HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright |
| **Bots** | Python-Skripte, Go-HTTP-Clients, cURL, wget, AhrefsBot, SEMRushBot, leere User-Agents |
| **Authentifizierung** | Brute-Force-Erkennung, Token-Leaks, Passwort-Offenlegung, Session-ID-Offenlegung |
| **DDoS** | Ratenbasierte Erkennung übermäßiger Anfragen |
| **Umgehung** | SQL-Kommentar-Einfügung, doppelte URL-Kodierung, HTML-Entity-Kodierung, Unicode-Escapes, IIS-Unicode, Hex-Escapes |
| **Sonstiges** | GraphQL-Introspection, Prototype-Pollution, Open Redirect, XXE, Web-Shells, Krypto-Mining, PII-Erkennung |
---
## Ausführen der Testsuite```bash
composer test
Das Paket enthält 335 Tests (856 Assertions), die Erkennungsmuster, Middleware-Verhalten, API-Endpunkte, Konfidenzbewertung, Ausschlussregeln, DDoS-Erkennung, Umgehungsresistenz, CVE-Muster, LDAP/XPath/SSTI-Injection, Bot-/Scanner-Erkennung, Probe-Tracking, Exportbefehle, Dashboard-Authentifizierung, sichere Felder, Leistungsoptimierungen und die vollständige HTTP-zu-DB-Verifizierung abdecken.
Lizenz
MIT-Lizenz. Siehe LICENSE für Details.
Mitwirken
Beiträge sind willkommen! Bitte reichen Sie einen Pull Request ein.
Danksagungen
- Jay Anta – Autor & Betreuer
- David van der Tuijn – Laravel-13-Unterstützung
- Alle Mitwirkenden