Shield Corev1.2.x
Arsitektur
Shield Core punya satu entry point: ShieldEngine::inspect(). Semua yang lain
mendukung fungsi itu. Halaman ini menjelaskan apa yang terjadi di dalamnya, dan
urutan kejadian itu penting.
Bentuk besar
Section titled “Bentuk besar”RequestContext │ ▼┌───────────────────────────────────────────────┐│ ShieldEngine::inspect() ││ ││ 1. Normalizer → NormalizedRequest ││ 2. ThreatSignatureEngine → RuleMatch[] ││ 3. allowlist? ── ya, keluar di sini ││ 4. validasi cookie tepercaya ││ 5. muat ban aktif → BanRecord ││ 6. gagal? → fail_mode ││ 7. RiskDecay::decayOffenseCount ││ 8. BehaviorDetector → BehaviorReport ││ 9. RiskScorer → ScoreBreakdown ││ 10. DecisionEngine → Verdict ││ 11. penyesuaian mode bot ││ 12. persist: log + tegakkan ban ││ ││ ▼ ││ EngineResult │└───────────────────────────────────────────────┘Urutan itu penting
Section titled “Urutan itu penting”1. Normalisasi lebih dulu
Section titled “1. Normalisasi lebih dulu”Tidak ada satu pun matcher yang melihat URI mentah. Normalizer memecah
request, mendekode ulang, menyamakan huruf besar-kecil, lalu menghasilkan
NormalizedRequest. Ini alasannya /%2e%65nv harus dibaca sebagai /.env.
Semua pencocokan berikutnya bekerja pada bentuk yang sudah rapi. Detailnya ada di Konfigurasi bagian normalisasi.
2. Signature sebelum perilaku
Section titled “2. Signature sebelum perilaku”Rule dicocokkan lebih dulu karena biayanya murah dan hasilnya pasti. Kalau
sudah ada rule critical yang cocok, hitungan perilaku tidak akan mengubah
keputusan itu.
3. Allowlist keluar lebih awal — dengan satu pengecualian
Section titled “3. Allowlist keluar lebih awal — dengan satu pengecualian”Kalau request berada di allowlist.paths atau allowlist.hosts, engine
mengembalikan ALLOW seketika dengan skor 0. Tidak ada query database,
tidak ada scoring.
Tapi bukan kalau ada rule critical. Baris kodenya secara eksplisit
meminta hasCriticalMatch() lebih dulu. Artinya allowlist tidak bisa dipakai
untuk membuka /.env — cacat konfigurasi yang sangat mudah terjadi.
if ($this->isAllowlisted($request) && ! $hasCritical) { // keluar di sini}4. Cookie tepercaya dibaca, bukan diberikan
Section titled “4. Cookie tepercaya dibaca, bukan diberikan”Engine hanya memvalidasi cookie kalau trusted.enabled aktif dan cookie itu
memang dikirim. Nilai cookie diteruskan ke adapter lewat $options; engine
tidak membacanya sendiri dari $_COOKIE. Itu keputusan sadar supaya test tidak
perlu memanipulasi superglobal.
$result = $engine->inspect($context, $counters, [ 'request_id' => $requestId, 'trusted_cookie' => $cookieValue,]);5. Ban dimuat sebelum scoring
Section titled “5. Ban dimuat sebelum scoring”loadActiveBan() dipanggil setelah validasi cookie, bukan setelah decision.
Kalau BanRepository gagal, variabel $degraded ikut terisi — dan itu yang
dipakai langkah berikutnya.
6. Fail mode
Section titled “6. Fail mode”Kalau $degraded dan fail_mode adalah fail_closed, engine memblokir
dengan skor 99 dan alasan fail_closed.
Default-nya fail_open: request diteruskan. Alasannya praktis — errornya
mematikan seluruh situs dan sulit didiagnosis kalau tidak ada yang bisa diakses
untuk membaca log.
Pilihan ini ada karena beberapa adapter lebih memilih memblokir daripada melewatkan permintaan tanpa pemeriksaan sama sekali.
7. Pelusan offense
Section titled “7. Pelusan offense”offense_count pada ban aktif dihapus gradually berdasarkan usianya sebelum
dipakai untuk scoring. Ban yang sudah lama tidak langsung kembali ke angka
nol, dan ini disengaja.
8 dan 9. Perilaku, lalu skor
Section titled “8 dan 9. Perilaku, lalu skor”Dua langkah terpisah, dan urutannya tidak dapat ditukar: BehaviorDetector
menghasilkan BehaviorReport (sinyal mentah), lalu RiskScorer mengubah
sinyal itu plus signature plus riwayat menjadi satu angka.
Kalau Anda mengganti salah satunya, jangan gabungkan. Detailnya ada di Deteksi Perilaku dan Skor & Keputusan.
10. Keputusan
Section titled “10. Keputusan”DecisionEngine menerima DecisionInput lengkap dan mengembalikan Verdict
yang punya dua lapis:
| Properti | Arti |
|---|---|
intended |
Apa yang seharusnya terjadi menurut skor. |
decision |
Apa yang benar-benar terjadi setelah mode diterapkan. |
Dua lapis inilah yang membuat observe bekerja tanpa mengubah kode pemanggil.
Ketika observe aktif, intended masih TEMP_BAN, tapi decision turun jadi
OBSERVE.
11. Penyesuaian mode bot
Section titled “11. Penyesuaian mode bot”Setelah keputusan diambil, ada satu koreksi khusus untuk crawler. Ini menyangkut klaim bot yang tidak bisa diverifikasi:
bot_mode = challenge→ hasilnyaCHALLENGE, tapi hanya kalau keputusan sebelumnya bukan terminal. Ban aktif tidak pernah diturunkan jadi challenge.bot_mode = observe→ hasilnya turun keOBSERVE, tapi hanya kalau tidak ada ban aktif dan tidak ada rule yang cocok.
Pengecualian itu penting. Tanpa itu, crawler sah yang kebetulan gagal reverse-DNS akan tersingkir dari hasil pencarian hanya karena jumlah URI yang dikunjunginya naik. Shield sengaja tidak mau melakukan itu — hilangnya Googlebot dari indeks lebih sulit dideteksi daripada beberapa request yang lolos.
12. Persist
Section titled “12. Persist”Terakhir, setelah keputusan final. Dua hal yang mungkin terjadi:
- Log, sesuai
logging.level. Default hanya menyimpan keputusan yang bukanALLOWbiasa. Mencatat semua request membuat tabel kejadian tumbuh tanpa batas dan justru menutupi baris yang Anda butuhkan. - Tegakkan ban. Kalau keputusan memblokir, ban baru ditulis. Kalau ban
aktif tapi request ini diizinkan, ban-nya hanya disentuh (
touchLastSeen), diperpanjang, atau dilepas — tergantung aturan. Riwayat tidak pernah dihapus.
Result-nya
Section titled “Result-nya”EngineResult adalah value object yang immutable. Yang paling sering Anda
periksa:
$result->verdict->decision; // apa yang harus dilakukan$result->verdict->reason; // kode alasan yang bisa disimpan$result->score->total; // hasil penjumlahan, tanpa plafon$result->score->matchedRuleIds; // rule yang cocok$result->score->behaviorSignals; // sinyal perilaku$result->matches; // detail setiap kecocokan$result->activeBan; // ban yang berlaku, kalau ada$result->trusted; // apakah pengenal valid$result->infrastructureDegraded; // apakah ada contract yang gagalEmpat method lain
Section titled “Empat method lain”| Method | Gunanya |
|---|---|
releaseBan($ip, $reason, $actor) |
Melepas ban aktif. Mengembalikan false kalau tidak ada ban aktif atau BanRepository null. |
markChallengePassed($ip) |
Melepas ban dan mencatat waktu kelulusan challenge. |
issueTrustedCookie($request) |
Membuat nilai cookie tepercaya baru. |
trustedCookieName() |
Nama cookie untuk header Set-Cookie. Default shield_trusted. |
markChallengePassed tidak menghapus riwayat. Ban yang dilepas tetap ada di
tabel dengan penanda, supaya operator bisa melihat orang yang sama pernah
diblokir tiga kali bulan ini.
Yang bukan urusan engine
Section titled “Yang bukan urusan engine”Beberapa hal sengaja tidak ada di Core, dan itu bukan kelemahan:
| Urusan | Dimana |
|---|---|
Pembacaan $_SERVER, getallheaders(), php://input |
Adapter |
| Cache, database, antrian | Adapter |
| Halaman HTML challenge | Adapter |
| Perintah CLI | Adapter |
| Pengiriman notifikasi | Adapter |
Alasannya sederhana: semuanya berbeda tiap framework, dan bagian yang perlu tetap sama persis antar framework. Daftar rule, scoring, dan urutan keputusan itulah intinya.
Angka yang harus Anda ingat
Section titled “Angka yang harus Anda ingat”| Batas | Default |
|---|---|
thresholds.challenge |
10 |
thresholds.ban |
20 |
thresholds.strong_ban |
30 |
escalation.step |
5 |
ban.durations |
15, 60, 360, 1440 menit |
performance.ban_cache_ttl_seconds |
30 |
response_code |
404 |
Skor tidak dibatasi di 100. Totalnya adalah penjumlahan sederhana:
$total = $signatureScore + $behavior->totalDelta + $escalationScore + $challengePenalty;Karena tidak ada plafon, satu request bisa langsung melewati strong_ban.
Itu memang perilaku yang diinginkan — tidak perlu menumpuk banyak sinyal
untuk memblokir request yang sudah jelas berbahaya.
Skor eskalasi dari riwayat offense adalah bagian yang sering terlewat:
$escalationScore = min($offenseCount, 5) * $config->escalationStep;Jadi offense ke-1 menambah 5, ke-2 menambah 10, dan berhenti di 25 poin setelah ke-5. Plafon itu ada supaya IP yang sudah pernah beberapa kali diblokir tidak perlu menunggu skor tinggi lagi untuk ban berikutnya.
Nilai standarnya bisa Anda ubah. Yang tidak bisa diubah adalah urutannya:
challenge selalu sebelum ban, ban selalu sebelum ban kuat, dan observe
selalu menurunkan, tidak pernah menaikkan.
Powered by PT Ganadev Multi Solusi