Lewati ke konten

Shield Corev1.2.x

Deteksi Perilaku

Rule mengenali request yang terlihat berbahaya. Perilaku mengenali pola — dan itu yang tidak bisa dilakukan satu request saja.

Scanner otomatis selalu mengirim ratusan request dan setiap kelihatan wajar. Yang membedakannya adalah request ke-101, ke-102, dan seterusnya, ke URL yang saling tidak berhubungan.

Lapis Sumber Cukup satu request?
Signature Rule Ya.
Perilaku Counter dalam jendela waktu Tidak.

BehaviorDetector menerima counter yang sudah dihitung adapter dari cache, lalu mengubahnya menjadi BehaviorReport:

$report = $behavior->evaluate($context, $normalized, $counters, $config);
$report->totalDelta; // jumlah skor
$report->signals; // nama sinyal yang aktif
$report->knownCrawler; // nama bot, kalau terdeteksi
Sinyal Pemicu Skor
unique_uri_burst URI berbeda melewati unique_uri_limit (25) 12
not_found_enumeration 404 melewati not_found_limit (20) 10
sensitive_path_burst Path sensitif melewati sensitive_path_rate_limit (8) 10
path_rate_burst Path biasa melewati path_rate_limit (30) 8
method_anomaly Method di luar GET, POST, HEAD, OPTIONS 4
scanner_tool_ua User-Agent bernama scanner 4
unverified_crawler_claim Mengaku bot, gagal diverifikasi 4
missing_headers Tidak ada User-Agent 2
suspicious_user_agent User-Agent generik atau ganjil 2
missing_referer POST tanpa referrer 2
oversized_request URI melewati batas panjang 2
known_crawler Bot dikenali 0
verified_crawler Bot diverifikasi lewat DNS 0

Dua sinyal terakhir bernilai nol karena memang tidak menambah skor — tapi merekam fakta yang nanti dipakai mode bot.

Tiga sinyal bernilai 2 dan itu disengaja:

  • missing_headers — beberapa klien sah tidak mengirim User-Agent.
  • suspicious_user_agent — curl, wget, dan python-requests sangat umum, termasuk untuk integrator sah. Memblokirnya sendirian akan merusak.
  • missing_referer — beberapa form memang tidak mengirim referrer.

Masing-masing bernilai 2, jadi tiga sinyal lemah itu masih di bawah lantai CHALLENGE yang besarnya 10. Sinyal tanpa rule tidak akan pernah membuat ban.

Inilah alasan RiskScorer memakai MIN_ESCALATION_BEHAVIOR_SCORE = 10 sebelum menganggap perilaku sebagai pelanggaran yang layak menaikkan skor eskalasi.

scanner_tool_ua berbeda dari suspicious_user_agent

Section titled “scanner_tool_ua berbeda dari suspicious_user_agent”

Keduanya membaca User-Agent, tapi bedanya jelas:

Pemicu Skor
scanner_tool_ua sqlmap, nikto, metasploit, wpscan, dirbuster, gobuster, masscan, nmap, nessus, acunetix, x00c, zgrab, httpx 4
suspicious_user_agent curl/, wget, python-requests, scrapy, go-http-client, node-fetch, axios, okhttp, powershell, java/, dan Mozilla/5.0 polos 2

Perbedaannya: orang yang menyebut tool scanner sedang berada di jalur yang salah dan tahu apa yang dilakukan, sedangkan curl cuma klien HTTP biasa.

Mozilla/5.0 tanpa tambahan apa pun juga ditandai. Hampir tidak ada browser sungguhan yang mengirim User-Agent persis seperti itu.

Kalau path masuk skip_paths, seluruh perilaku dilewati:

'rules' => [
'skip_paths' => ['/api/webhook/payment'],
],

Rule tetap berlaku — yang dimatikan hanya hitungan perilaku.

Alasannya terlihat di kode: counter di-key berdasarkan IP, sedangkan endpoint seperti OAuth atau gerbang antar layanan dipakai banyak klien sah sekaligus. Volume di sana bukan mencerminkan satu pelaku.

if ($counters->isSensitivePath
&& $counters->pathRequestCount >= $config->sensitivePathRateLimit) {
// 10 poin
} elseif ($counters->pathRequestCount >= $config->pathRateLimit) {
// 8 poin
}

Path yang sensitif hanya menghasilkan sensitive_path_burst. Ia tidak sekaligus dapat path_rate_burst. Jadi 18, bukan 10 + 8.

Ini bagian paling penting dari halaman ini. Kalau bot dikenali dan verifikasi DNS berhasil, evaluate() langsung keluar:

return new BehaviorReport(
totalDelta: 0,
signals: [SIGNAL_KNOWN_CRAWLER, SIGNAL_VERIFIED_CRAWLER],
knownCrawler: $knownCrawler,
);

Semua delta dinolkan, termasuk yang sudah dihitung sebelumnya. Googlebot sungguhan lalu boleh crawl agresif tanpa pernah tersentuh challenge atau ban, karena mengindeks memang butuh banyak request.

Kalau verifikasi gagal, yang terjadi justru sebaliknya: sinyal unverified_crawler_claim sebesar 4, lalu mode bot yang memutuskan apa yang dilakukan kepada crawler itu. Detailnya ada di Verifikasi Crawler.

BehaviorDetector tidak menghitung apa pun. Adapter Anda yang punya tanggung jawab ini, dari cache:

use Ganadev\Shield\Core\Detection\BehaviorCounters;
$counters = new BehaviorCounters(
uniqueUriCount: $cache->get("uri:{$ip}") ?? 0,
notFoundCount: $cache->get("404:{$ip}") ?? 0,
pathRequestCount: $cache->get("path:{$ip}:{$path}") ?? 0,
isSensitivePath: $this->isSensitive($path),
);

Tiga counter pertama berbasis IP, yang ketiga per-path. Jendelanya behavior.window_seconds, yang bawaannya 60 detik.

isSensitivePath bisa Anda ambil dari config.behavior.sensitive_paths. Daftar default-nya /login, /wp-login.php, /admin/login, /administrator/, /api/login, /api/auth, dan /user/login.

Kalau situs Anda punya traffic tinggi, satu IP bisa muncul sebagai “unique URI banyak” karena memang benar:

'behavior' => [
'unique_uri_limit' => 60,
'not_found_limit' => 40,
],

Naikkan satu per satu dan lihat hasilnya di laporan.

Kalau API Anda dipanggil dari browser, suspicious_user_agent tidak akan muncul karena Accept dan User-Agent berasal dari klien yang sama. Kalau Anda punya endpoint yang memang bukan halaman web, masukkan ke skip_paths.

Tim keamanan internal Anda memindai situs sendiri? Jangan matikan scanner_tool_ua secara global. allowlist.ips lebih tepat — perilaku dimatikan untuk IP itu saja, signature tetap berlaku.

Perilaku tidak pernah cukup untuk memblokir request pertama dari IP baru. Selalu ada dua lapis: signature untuk request ini, perilaku untuk history.

Kalau log Anda menunjukkan score_challenge tanpa matchedRuleIds apa pun, itu perilaku murni. Buka Skor & Keputusan untuk memahami kenapa itu terjadi dan bagaimana menanganinya.

Powered by PT Ganadev Multi Solusi