Shield Corev1.2.x
Ban & Risk Decay
Ban adalah bagian dari Shield yang paling mudah disalahpahami. Dua hal yang paling sering tidak terduga:
- Melepas ban tidak mereset riwayat.
- Ban tidak langsung menolak — ia menaikkan jadi challenge dulu.
Keduanya disengaja, dan keduanya dijelaskan di bawah.
Status ban
Section titled “Status ban”enum BanStatus: string{ case Active = 'active'; case Expired = 'expired'; case Released = 'released'; case ManualBlock = 'manual_block';}| Status | Arti |
|---|---|
active |
Sedang berlaku dan ditegakkan. |
expired |
Sudah lewat expires_at sendiri. |
released |
Dilepas manual oleh operator. |
manual_block |
Diblokir manual, biasanya karena alasan di luar sistem. |
Perhatikan bahwa expired dan released tetap ada di database. Keduanya
hanya berbeda dari mana asalnya.
Empat penghitung pada satu ban
Section titled “Empat penghitung pada satu ban”BanRecord menyimpan lebih dari sekadar status:
| Field | Arti |
|---|---|
violationCount |
Berapa kali request mencurigakan datang selama ban ini aktif. |
offenseCount |
Berapa kali IP ini pernah kena ban, lintas riwayat. |
riskScore |
Skor terakhir yang dihitung. |
challengePassedAt |
Kapan challenge terakhir berhasil dilalui. |
Pembeda antara violationCount dan offenseCount penting:
violationCountbertambah selama ban aktif. Ini menunjukkan seberapa gigih orang itu mencoba.offenseCountbertambah setiap kali ban baru dibuat. Ini yang menentukan durasi ban berikutnya.
Durasi ban
Section titled “Durasi ban”public function durationFor(int $offenseCount, array $durationsMinutes): int{ $index = max(0, $offenseCount - 1);
return $durationsMinutes[min($index, count($durationsMinutes) - 1)];}Dengan ban.durations bawaan [15, 60, 360, 1440]:
| Offense ke- | Durasi |
|---|---|
| 1 | 15 menit |
| 2 | 1 jam |
| 3 | 6 jam |
| 4 | 24 jam |
| 5 ke atas | 24 jam (entri terakhir dipakai terus) |
Perhatikan min($index, count - 1). Setelah daftar habis, durasi terakhir
dipakai selamanya. Menambah entri baru di tengah daftar mengubah durasi ban
yang sedang berlaku — hati-hati kalau Anda memutuskan menambahnya saat
production.
Riwayat tidak pernah dihapus
Section titled “Riwayat tidak pernah dihapus”public function nextOffenseCount(?BanRecord $previous): int{ if ($previous === null) { return 1; }
return $previous->offenseCount + 1;}Melepas ban hanya mengubah status jadi released dan mengisi released_at.
Penghitungnya tetap utuh.
Konsekuensinya: orang yang dilepas secara manual akan kembali dengan durasi yang lebih lama kalau dia offense lagi. Ini disengaja — kalau riwayat direset setiap kali operator membantu, ban berhenti jadi hukuman.
Buat Anda yang mengoperasikan: melepas ban bukan berarti mengampuni. Kalau Anda ingin IP yang sama untuk sementara tidak diblokir lagi, itu perkara lain daripada melepas ban.
Pelusan risiko
Section titled “Pelusan risiko”RiskDecay punya dua method, dengan jendela waktu berbeda.
Pelusan offense
Section titled “Pelusan offense”decayOffenseCount( int $offenseCount, \DateTimeImmutable $lastSeen, \DateTimeImmutable $now, int $decayWindowSeconds = 86400, // 24 jam int $decayPerWindow = 1,): intSatu offense hilang setiap 24 jam tanpa aktivitas. Jadi IP yang diblokir hari
Senin dan tidak kembali sampai Rabu pagi punya offenseCount satu lebih
kecil.
Ini yang mencegah penghakiman selamanya. Tanpa pelusan, satu kesalahan konfigurasi di bulan Maret akan membuat IP itu kena ban 24 jam selamanya di bulan Juni.
Pelusan skor
Section titled “Pelusan skor”decayScore( int $score, \DateTimeImmutable $lastSeen, \DateTimeImmutable $now, int $decayWindowSeconds = 3600, // 1 jam int $decayPerWindow = 10,): intSepuluh poin hilang setiap jam tanpa aktivitas.
Dua jendela itu punya alasan berbeda: skor mereda cepat supaya request berikutnya tidak langsung kena ban, sementara offense mereda lambat supaya riwayat tetap berarti.
Keduanya tidak pernah turun di bawah nol:
return max(0, $offenseCount - ($windows * $decayPerWindow));Pelusan dihitung, bukan disimpan
Section titled “Pelusan dihitung, bukan disimpan”Nilai yang meluruh tidak ditulis ulang ke database. ShieldEngine menghitungnya
saat dibutuhkan:
$offenseCount = $activeBan === null ? 0 : $this->riskDecay->decayOffenseCount( $activeBan->offenseCount, $activeBan->lastSeenAt, $this->clock->now(),);Jadi kalau Anda membuka dashboard dan melihat angka lama di sana, itu bukan berarti pelusan tidak jalan — cuma belum ada request baru dari IP itu untuk menghitung ulang.
Tinjauan manual
Section titled “Tinjauan manual”public const MANUAL_REVIEW_THRESHOLD = 5;Setelah lima offense, ban baru disimpan dengan metadata
manual_review: true:
$metadata = ['manual_review' => $this->banPolicy->requiresManualReview($offenseCount)];Perlu ditegaskan: metadata ini tidak mengubah cara ban berakhir. Ban tetap
kedaluwarsa sesuai jadwalnya, dan pada offense kelima durasi sudah mentok di
nilai terakhir ban.durations (bawaannya 1440 menit / 24 jam). Yang dilakukan
metadata tersebut hanya penanda bagi aplikasi Anda — dan bagi siapa pun yang
membaca tabel ban — bahwa IP ini layak diperiksa manusia sebelum dikembalikan.
Tujuannya jelas: pola serangan otomatis yang sophisticated biasanya memerlukan banyak percobaan. Lima offense dari IP yang sama layak dilihat oleh manusia sebelum dikembalikan.
Cache 30 detik
Section titled “Cache 30 detik”Ban aktif di-cache selama performance.ban_cache_ttl_seconds, bawaannya 30
detik.
Ini menjelaskan gejala yang sering dikeluhkan: “ban sudah saya lepas tapi IP
masih diblokir”. Cache-nya belum kedaluwarsa. php artisan cache:clear
menyelesaikannya.
Nilai 30 detik dipilih sebagai kompromi: cukup untuk menutup celah di mana beberapa request paralel lolos sebelum ban tercatat, dan cukup pendek supaya tindakan manual terasa langsung.
Tiga operasi yang sering dipakai
Section titled “Tiga operasi yang sering dipakai”// Melepas ban aktif.$engine->releaseBan($ip, $reason, $actor);
// Melepas ban DAN mencatat bahwa challenge berhasil dilalui.// Riwayat tetap tersimpan.$engine->markChallengePassed($ip);
// Membuat cookie tepercaya setelah challenge.$cookie = $engine->issueTrustedCookie($request);releaseBan() dan markChallengePassed() mengembalikan false kalau
BanRepositoryInterface null atau tidak ada ban aktif untuk IP itu. Cek
nilai kembalinya sebelum mengabarui UI.
Yang perlu diingat
Section titled “Yang perlu diingat”Ban tidak menyentuh signature
Section titled “Ban tidak menyentuh signature”Kalau request mencocokkan rule critical, ban yang sedang aktif tidak
menghinderinya. Ban berlaku pada request biasa; signature berlaku pada
segala hal.
Durasi dibaca dari urutan offense, bukan dari skor
Section titled “Durasi dibaca dari urutan offense, bukan dari skor”IP dengan skor 45 dan offense pertama tetap dapat ban 15 menit. Yang menentukan durasi hanya berapa kali dia sudah pernah kena ban.
violationCount adalah sinyal, bukan hukuman
Section titled “violationCount adalah sinyal, bukan hukuman”Penyerang yang coba 200 kali selama ban aktif punya violationCount 200. Itu
berguna untuk laporan dan untuk melihat pola, tapi tidak mengubah durasi.
Jangan pernah menghapus baris ban
Section titled “Jangan pernah menghapus baris ban”Kalau Anda menghapus, offenseCount ikut hilang dan durasi ban berikutnya
kembali ke 15 menit. Gunakan release, jangan delete.
Berikutnya
Section titled “Berikutnya”- Skor & Keputusan — dari mana skor yang tersimpan itu datang.
- Model Keamanan — batasannya.
Powered by PT Ganadev Multi Solusi