rilo-arbabillah / laravel-crowdsec
A lightweight CrowdSec-like WAF protection package for Laravel
Requires
- php: ^8.1
- illuminate/console: ^10.0|^11.0
- illuminate/contracts: ^10.0|^11.0
- illuminate/database: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.10
- guzzlehttp/psr7: ^2.9
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
- dev-master
- 1.0.0
- dev-feat/46-deep-inspection
- dev-feat/49-audit-log
- dev-feat/48-prometheus-metrics
- dev-feat/50-doctor-command
- dev-feat/35-laravel-12-support
- dev-chore/38-stable-release
- dev-security/37-redos-audit
- dev-task/36-improve-test-coverage
- dev-feature/12-admin-dashboard
- dev-feature/14-rest-api
- dev-feature/13-geoip-lookup
- dev-feature/17-siem-export
- dev-feature/11-per-route-rate-limit
- dev-feature/16-honeypot-routes
- dev-feature/15-custom-patterns
- dev-feature/8-notification-support
- dev-feature/7-event-system
- dev-feature/9-score-decay
- dev-feature/10-scheduled-cleanup
- dev-feature/4-caching-layer
- dev-feature/2-edge-case-tests
- dev-feature/1-integration-tests
- dev-task/3-performance-benchmark
- dev-chore/5-setup-ci-pipeline
This package is auto-updated.
Last update: 2026-03-11 13:40:27 UTC
README
A lightweight, CrowdSec-like Web Application Firewall (WAF) protection package for Laravel applications. This package provides real-time threat detection and IP blocking based on WAF patterns and behavior analysis.
Features
- WAF Pattern Detection: Detects SQL injection, XSS, path traversal, command injection, and 11 more attack types
- IP Blocking: Temporary IP blocks with automatic expiration and progressive escalation
- Behavior-based Protection: Rate limiting, brute-force detection, and threat score tracking with auto-decay
- Caching Layer: Cached blocked IP lookups for high-traffic applications
- Event System: 4 Laravel events (ThreatDetected, IpBlocked, IpUnblocked, BehaviorThresholdExceeded)
- Notifications: Email and Slack alerts with severity filtering and rate limiting
- Honeypot Routes: Trap routes to catch automated scanners
- Per-Route Rate Limiting: Configurable rate limits via middleware (
crowdsec.rate:60,1) - Custom Patterns: Register custom detection scenarios at runtime
- GeoIP Lookup: IP geolocation via ip-api.com with caching
- REST API: 6 API endpoints for programmatic management (block, unblock, check, stats, events, blocked)
- Admin Dashboard: Standalone dark theme Blade dashboard (enable via config)
- SIEM Export: Export events in JSON, CSV, or Syslog (RFC 5424) format
- CLI Commands: Statistics, cleanup, and export utilities
- Facade API: Easy programmatic access to all features
- Auto-migrations: Database tables created automatically
- CI Pipeline: GitHub Actions with PHP 8.1/8.2/8.3 × Laravel 10.x/11.x matrix
Requirements
- PHP ^8.1
- Laravel ^10.0 or ^11.0
- MySQL/PostgreSQL/SQLite (any Laravel-supported database)
Installation
Install the package via Composer:
composer require rilo-arbabillah/laravel-crowdsec
The package will automatically register its service provider and facade.
Configuration
Publish the configuration file to customize detection scenarios and thresholds:
php artisan vendor:publish --tag=crowdsec-config
This will create config/crowdsec-scenarios.php where you can:
- Enable or disable the package
- Configure detection patterns for each attack type
- Adjust behavior thresholds (request limits, 404 limits, login attempts)
- Set block durations per severity
- Whitelist IPs that should never be blocked
Enabling/Disabling the Package
You can toggle the package on or off via configuration:
// config/crowdsec-scenarios.php return [ // Enable or disable the entire package 'enabled' => true, // Set to false to disable all protection // ... rest of configuration ];
When disabled, the middleware will pass all requests through without any filtering or blocking. This is useful for:
- Development environments where you need to test without WAF interference
- Debugging specific issues without protection blocking legitimate traffic
- Temporary maintenance windows
Default Configuration
// config/crowdsec-scenarios.php return [ // Enable/disable the package 'enabled' => true, // Whitelist IPs (won't be blocked) 'whitelist_ips' => [ '127.0.0.1', '::1', ], // Behavior thresholds 'behavior' => [ 'request_threshold' => 500, // requests per minute '404_threshold' => 15, // 404s per minute 'login_threshold' => 5, // login attempts per minute 'threat_score_threshold' => 50, 'block_duration' => 240, // 4 hours 'severity' => 'high', ], // Block duration defaults (in minutes) 'defaults' => [ 'low' => 60, 'medium' => 240, 'high' => 720, 'critical' => 1440, ], // ... detection patterns ];
Basic Usage
Applying Middleware to Routes
Apply the middleware to individual routes:
use Illuminate\Support\Facades\Route; Route::middleware(['crowdsec'])->group(function () { Route::get('/admin', function () { // Protected route }); Route::post('/login', [AuthController::class, 'login']); });
Applying Middleware Globally
Add the middleware to your HTTP kernel for global protection:
// app/Http/Kernel.php protected $middlewareAliases = [ // ... 'crowdsec' => \RiloArbabillah\LaravelCrowdSec\Http\Middleware\CrowdSecProtection::class, ];
Then apply to routes or route groups:
// Protect all web routes Route::middleware(['crowdsec'])->group(base_path('routes/web.php')); // Protect API routes Route::middleware(['api', 'crowdsec'])->group(base_path('routes/api.php'));
Skipping Middleware for Certain Routes
// Disable for health check endpoints Route::middleware(['crowdsec'])->group(function () { Route::get('/admin', function () { // Protected }); }); Route::get('/health', function () { // Not protected })->withoutMiddleware(['crowdsec']);
Programmatic Usage
Use the CrowdSec facade for programmatic control:
Check if IP is Blocked
use RiloArbabillah\LaravelCrowdSec\Facades\CrowdSec; $ip = request()->ip(); if (CrowdSec::isBlocked($ip)) { abort(403, 'Your IP has been blocked'); }
Manually Block an IP
use RiloArbabillah\LaravelCrowdSec\Facades\CrowdSec; // Block for 60 minutes CrowdSec::blockIp($request->ip(), 'Manual ban - spam', 60); // Block for 24 hours (default for critical threats) CrowdSec::blockIp($request->ip(), 'Suspicious activity', 1440);
Unblock an IP
use RiloArbabillah\LaravelCrowdSec\Facades\CrowdSec; CrowdSec::unblockIp($ip);
Track Login Attempts
Call this after failed login attempts for brute-force protection:
use RiloArbabillah\LaravelCrowdSec\Facades\CrowdSec; public function login(Request $request) { if (! Auth::attempt($credentials)) { // Track failed attempt CrowdSec::trackLoginAttempt($request->ip()); return back()->withErrors(['email' => 'Invalid credentials']); } // Reset login attempts on successful login // (optional - you could implement this) return redirect('/dashboard'); }
Analyze Request for Threats
use RiloArbabillah\LaravelCrowdSec\Facades\CrowdSec; $threats = CrowdSec::analyzeRequest($request); if (! empty($threats)) { foreach ($threats as $threat) { \Log::warning('Security threat detected', [ 'type' => $threat['type'], 'severity' => $threat['severity'], 'matched' => $threat['matched'], ]); } }
CLI Commands
View Protection Statistics
php artisan crowdsec:stats
Output includes:
- Active blocked IPs
- Expired blocked IPs
- Events today
- Events this week
- Top attackers (IP addresses)
For JSON output (useful for monitoring):
php artisan crowdsec:stats --json
Clean Up Expired Bans
Remove expired IP blocks and old security events:
php artisan crowdsec:cleanup
Cleanup Options
# Preview what would be deleted (no changes) php artisan crowdsec:cleanup --dry-run # Clean only expired bans php artisan crowdsec:cleanup --expired # Clean only old events (older than 30 days) php artisan crowdsec:cleanup --old-events # Clean only old behaviors (older than 7 days) php artisan crowdsec:cleanup --old-behaviors
Automated Cleanup in Production
Add to your routes/console.php or set up a scheduled command:
// In routes/console.php Artisan::command('crowdsec:daily-cleanup', function () { $this->call('crowdsec:cleanup', ['--expired' => true]); })->purpose('Clean up expired bans daily');
Or use Laravel's scheduler:
// In app/Console/Kernel.php protected function schedule(Schedule $schedule) { $schedule->command('crowdsec:cleanup --expired')->daily(); }
Database
The package creates three tables automatically via migrations:
| Table | Description |
|---|---|
blocked_ips |
Tracks blocked IPs with expiration and reason |
ip_behaviors |
Tracks per-IP metrics (request count, 404s, login attempts, threat score) |
security_events |
Logs all detected security threats |
Tables are created when you run:
php artisan migrate
Detected Threats
The package detects the following attack types:
| Threat Type | Severity | Examples |
|---|---|---|
| SQL Injection | Critical | UNION SELECT, OR 1=1, xp_cmdshell |
| XSS | High | <script>, javascript:, onclick= |
| Path Traversal | Critical | ../, %2e%2e%2f |
| Command Injection | Critical | ;cat, |whoami, `id` |
| File Inclusion | High | php://input, data:text/html |
| PHP Serialization | Critical | O:16:"MaliciousClass" |
| Directory Bruteforce | Medium | .git/config, .env, wp-admin |
| Header Injection | High | CRLF injection, Location: |
| Suspicious User Agent | Medium | sqlmap, nmap, python-requests |
| Behavior Threshold | High | Rate limiting, brute-force |
Production Guidelines
1. Monitor Regularly
Run stats command periodically or set up monitoring:
# Check for active threats php artisan crowdsec:stats # Export to monitoring system php artisan crowdsec:stats --json | jq '.events_today'
2. Tune Thresholds for Production
Adjust config/crowdsec-scenarios.php based on your traffic:
'behavior' => [ 'request_threshold' => 1000, // Increase for high-traffic sites '404_threshold' => 20, // Adjust based on your 404 rate 'login_threshold' => 3, // Stricter for login pages 'threat_score_threshold' => 50, 'block_duration' => 240, ],
3. Whitelist Internal Services
'whitelist_ips' => [ '127.0.0.1', '::1', '10.0.0.0/8', // Internal network '192.168.0.0/16', // Internal network 'your-load-balancer-ip', ],
4. Set Up Log Monitoring
Monitor Laravel logs for CrowdSec warnings:
// Log channel configuration 'log' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => 'warning', ],
5. Schedule Regular Cleanup
// In app/Console/Kernel.php protected function schedule(Schedule $schedule) { // Clean expired bans daily at 3 AM $schedule->command('crowdsec:cleanup --expired --old-events --old-behaviors') ->daily() ->at('03:00'); }
6. Performance Considerations
- The middleware runs on every request - keep patterns optimized
- IP whitelist is checked first for performance
- Behavior tracking uses efficient increment operations
- Consider caching blocked IPs for very high-traffic sites
Performance Benchmarks
The package includes a benchmark suite (tests/Benchmark) to verify overhead stays minimal.
Run benchmarks:
vendor/bin/phpunit tests/Benchmark --testdox
Typical results (100 iterations average):
| Operation | Avg Time | Target |
|---|---|---|
| Whitelist bypass | ~0.006ms | < 0.5ms ✅ |
| Clean request analysis | ~0.038ms | < 2ms ✅ |
| Blocked IP check | ~0.045ms | < 2ms ✅ |
| Threat detection (SQLi) | ~0.047ms | < 5ms ✅ |
| Multi-threat detection | ~0.051ms | < 5ms ✅ |
| POST body analysis | ~0.159ms | < 3ms ✅ |
| Behavior tracking | ~0.163ms | < 3ms ✅ |
Note: Results may vary depending on hardware. Benchmarks use SQLite in-memory.
Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-new-feature - Make your changes
- Run tests:
composer test - Commit your changes:
git commit -am 'Add some feature' - Push to the branch:
git push origin feature/my-new-feature - Submit a Pull Request
Running Tests
composer test
Security
If you discover any security-related issues, please email the maintainer instead of opening an issue.
License
This package is open-sourced software licensed under the MIT license.