bale / gupa
Guardian — IP protection, rate limiting, and bot detection for Bale landing pages
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0||^13.0
Requires (Dev)
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
This package is auto-updated.
Last update: 2026-07-31 03:00:26 UTC
README
Perlindungan IP, rate limiting, dan deteksi bot untuk aplikasi Laravel.
Gupa (dari Sansekerta gup — melindungi) adalah lapisan keamanan komprehensif yang secara otomatis memberi skor pada setiap request, memblokir aktor jahat, dan menyediakan visibilitas real-time terhadap ancaman di aplikasi Anda.
Bagian dari ekosistem Bale. Dapat digunakan di proyek Laravel 11/12/13 mana pun.
Fitur
- Mesin Skor Perilaku — Sistem multi-detektor yang mengevaluasi setiap request secara real-time
- 5 Detektor Bawaan — Velocity, honeypot, header HTTP, serangan 404, rate limiting
- Pemblokiran Otomatis — Blocking IP sementara atau permanen dengan threshold yang dapat dikonfigurasi
- Dual Storage — Mode cache-only (Redis/file) atau persistent (database)
- Dukungan CIDR & Wildcard — Whitelist/blacklist seluruh subnet atau range IP
- Blacklist/Whitelist Dinamis — Tambah atau hapus IP saat runtime melalui Artisan
- Logging Path Mencurigakan — Mencatat detail request saat skor mencapai threshold suspicious
- Notifikasi — Alert webhook dan email saat IP diblokir
- Dashboard & CLI — Pantau, query, dan kelola semuanya dari command line
Persyaratan
- PHP ^8.3
- Laravel 11, 12, atau 13
Instalasi
composer require bale/gupa php artisan gupa:setup
Wizard setup akan memandu Anda dalam pemilihan mode:
| Mode | Yang dilakukan |
|---|---|
| Auto (default) | Publish config dan env vars. Storage cache-only. |
| Advance | Auto + migrasi database + persistent storage. |
Mulai Cepat
Daftarkan middleware di bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) { $middleware->prepend(\Bale\Gupa\Middleware\GuardianMiddleware::class); })
Aktifkan di .env:
GUPA_ENABLED=true
Setiap request sekarang terlindungi secara otomatis.
Cara Kerja
Request → GuardianMiddleware → ScoreCalculator → Detectors → Skor
│
┌─────────────────┤
│ │
skor < threshold skor >= threshold
│ │
PASS Block IP (403)
Setiap detektor secara independen mengevaluasi request dan memberikan kontribusi skor. Ketika total skor mencapai threshold, IP diblokir.
Detektor
| Detektor | Apa yang ditangkap | Skor Default |
|---|---|---|
| Velocity | Request rate berlebihan | 30 |
| Honeypot | Field jebakan bot dan rute tersembunyi | 50 |
| Header | Header browser standar hilang, bot yang dikenal | 20 |
| NotFound | Pencarian 404 berulang | 15 per hit |
| RateLimit | Request melebihi batas rate | 25 |
Konfigurasi
Semua pengaturan ada di config/gupa.php dan dapat di-override melalui .env:
# Inti GUPA_ENABLED=true GUPA_THRESHOLD=100 # Total skor untuk trigger block GUPA_SCORE_DECAY_WINDOW=300 # Detik sebelum skor auto-reset (5 menit) GUPA_BLOCK_DURATION=3600 # Detik durasi block sementara (1 jam) GUPA_LOG_ENABLED=true # Storage GUPA_STORAGE=cache # "cache" atau "database" # Recidivist (permanent block setelah N block dalam M hari) GUPA_RECIDIVIST_DAYS=1 # Jendela waktu dalam hari (default: 1) GUPA_RECIDIVIST_THRESHOLD=3 # Jumlah block maks sebelum permanent (default: 3) # Logging path mencurigakan (hanya database mode) GUPA_SUSPICIOUS_THRESHOLD=10 # Log request saat skor mencapai ini GUPA_LOG_RETENTION_DAYS=30 # Auto-prune log lebih lama dari ini # Notifikasi GUPA_NOTIFY_WEBHOOK=false GUPA_NOTIFY_WEBHOOK_URL= GUPA_NOTIFY_EMAIL=false GUPA_NOTIFY_EMAIL_TO= # Nawasara Integration (opsional, ekosistem Kabupaten Ponorogo) GUPA_NAWASARA_ENABLED=false GUPA_NAWASARA_BASE_URL=https://nawasara.ponorogo.go.id/api/v1/secscan GUPA_NAWASARA_TOKEN= GUPA_NAWASARA_TIMEOUT=10
Nawasara Integration
Gupa mendukung sinkronisasi otomatis dengan Nawasara Security Center, ekosistem keamanan milik Kabupaten Ponorogo.
Ketika diaktifkan, setiap insiden block/unblock akan langsung dikirim ke Nawasara via API:
| Aksi | Endpoint | Method |
|---|---|---|
| Block IP | /api/v1/secscan/ip-blocks |
POST |
| Unblock IP | /api/v1/secscan/ip-blocks/{ip} |
DELETE |
| Lihat IP blokir | /api/v1/secscan/ip-blocks |
GET |
Aktifkan
GUPA_NAWASARA_ENABLED=true GUPA_NAWASARA_TOKEN=your-api-token-here
Integrasi dengan Command
Ketika Nawasara aktif, command gupa:blacklist dan gupa:unblock otomatis melakukan sinkronisasi:
# Blacklist + sync ke Nawasara php artisan gupa:blacklist --add=1.2.3.4 # Unblock + sync dari Nawasara php artisan gupa:unblock 1.2.3.4
Mode Storage
| Mode | Backend | Kelebihan | Kekurangan |
|---|---|---|---|
| cache | Redis / file | Tanpa beban DB, cepat | Hilang saat cache flush |
| database | SQLite / MySQL / PostgreSQL | Persistent, dapat di-query | Sedikit beban DB |
Whitelist & Blacklist
List statis melalui config:
// config/gupa.php 'whitelist' => [ 'enabled' => true, 'ips' => ['127.0.0.1', '::1', '10.0.0.0/8'], ], 'blacklist' => [ 'enabled' => true, 'ips' => ['192.168.1.*'], ],
List dinamis melalui Artisan:
# Blacklist — langsung blokir (whitelist otomatis dihapus jika ada) php artisan gupa:blacklist --add=1.2.3.4 php artisan gupa:blacklist --add=10.0.0.0/8 php artisan gupa:blacklist --remove=1.2.3.4 php artisan gupa:blacklist --list # Whitelist — lewati semua deteksi (blacklist otomatis dihapus jika ada) php artisan gupa:whitelist --add=10.0.0.1 php artisan gupa:whitelist --remove=10.0.0.1 php artisan gupa:whitelist --list
Menambah ke blacklist otomatis menghapus dari whitelist, dan sebaliknya.
Perintah Artisan
# Monitoring php artisan gupa:dashboard # Ikhtisar real-time php artisan gupa:dashboard --json # Output JSON php artisan gupa:stats # Ringkasan konfigurasi # Manajemen IP php artisan gupa:unblock 192.168.1.100 # Buka blokir IP sementara php artisan gupa:clear-score 192.168.1.100 # Reset skor tanpa unblock # Whitelist & Blacklist php artisan gupa:whitelist --add=10.0.0.1 php artisan gupa:whitelist --remove=10.0.0.1 php artisan gupa:whitelist --list php artisan gupa:blacklist --add=1.2.3.4 php artisan gupa:blacklist --remove=1.2.3.4 php artisan gupa:blacklist --list # Logging (database mode) php artisan gupa:log # Log terbaru php artisan gupa:log --ip=1.2.3.4 # Filter berdasarkan IP php artisan gupa:log --status=404 # Filter berdasarkan status code php artisan gupa:log --event=block # Filter berdasarkan tipe event php artisan gupa:log --days=7 # 7 hari terakhir php artisan gupa:log --prune # Hapus log lama php artisan gupa:log --json # Output JSON
Honeypot
Gupa mendeteksi bot melalui 3 cara: field tersembunyi, exact route match, dan prefix path.
Field Tersembunyi
Sembunyikan field jebakan di form Anda:
<x-gupa::honeypot /> {{-- Custom field name --}} <x-gupa::honeypot fieldName="email_backup" action="{{ route('contact.store') }}" />
Bot yang mengisi field tersembunyi akan mendapat skor 50.
Routes (Exact Match)
Salah satu segment path harus sama persis. Cocok untuk halaman admin atau endpoint yang jarang diakses user normal.
// config/gupa.php 'honeypot' => [ 'routes' => ['wp-login.php', 'xmlrpc.php'], ],
| Request | Terdeteksi? | Alasan |
|---|---|---|
/wp-login.php |
✓ | segment wp-login.php match |
/2023/wp-login.php |
✓ | segment wp-login.php match |
/sub/wp-login.php/x |
✓ | segment wp-login.php match |
/wp-login |
✗ | wp-login ≠ wp-login.php |
/login |
✗ | tidak ada segment yang match |
Prefixes (Awalan Segment)
Salah satu segment path harus diawali string tertentu. Cocok untuk memblokir seluruh grup path.
// config/gupa.php 'honeypot' => [ 'prefixes' => ['wp-', 'wpv-'], ],
| Request | Terdeteksi? | Alasan |
|---|---|---|
/wp-admin.php |
✓ | segment wp-admin.php diawali wp- |
/2023/wp-login.php |
✓ | segment wp-login.php diawali wp- |
/wp-content/uploads/x |
✓ | segment wp-content diawali wp- |
/wpv-view/123 |
✓ | segment wpv-view diawali wpv- |
/admin |
✗ | tidak ada segment yang diawali wp- |
/login |
✗ | tidak ada segment yang diawali wp- |
Gabungan Routes + Prefixes
Keduanya dicek secara bersamaan, skor tetap sama.
'honeypot' => [ 'routes' => ['xmlrpc.php', 'wp-login.php'], 'prefixes' => ['wp-', 'wpv-'], 'score' => 50, ],
Semua request ke path yang match akan mendapat skor 50, apakah dari routes maupun prefixes.
Coba Sendiri
1. Cek status
php artisan gupa:dashboard
2. Simulasi bot
# Request normal — lolos curl -I https://yourdomain.com # User agent bot — kena skor curl -I -A "python-requests/2.28" https://yourdomain.com # Header standar hilang — kena skor curl -I -H "Accept:" -H "Accept-Language:" https://yourdomain.com
3. Cek skor naik
php artisan gupa:dashboard --json
4. Force block diri sendiri (untuk testing)
php artisan gupa:blacklist --add=IP_ANDA # Buka browser → 403 Forbidden php artisan gupa:blacklist --remove=IP_ANDA # Akses pulih
5. Cek log
tail -f storage/logs/laravel.log | grep Gupa
Arsitektur
packages/bale-gupa/
├── config/gupa.php # Semua konfigurasi
├── database/migrations/ # 4 migrasi (database mode)
├── resources/views/ # Komponen Blade honeypot
├── src/
│ ├── Actions/ # BlockAction, LogAction, NotifyAction
│ ├── Commands/ # 8 perintah Artisan
│ ├── Detectors/ # 5 detektor (Velocity, Honeypot, Header, NotFound, RateLimit)
│ ├── Middleware/ # GuardianMiddleware (entry point)
│ ├── Models/ # BlockedIp, Log, Whitelist, Blacklist
│ ├── Notifications/ # Channel Webhook & Email
│ ├── Scorer/ # ScoreCalculator (orchestrator)
│ └── Support/ # WhitelistChecker, NawasaraService
└── tests/ # 125 tes (Pest)
Pengujian
cd packages/bale-gupa composer test
Lisensi
MIT