Mencegah scraping massal pada situs publik bertraffic tinggi bukan sekadar menambahkan CAPTCHA atau membatasi IP. Jika data sensitif waktu-rilis seperti daftar pemenang, hasil seleksi, atau halaman pengumuman bisa diakses lebih awal melalui pola request otomatis, masalahnya biasanya ada pada desain arsitektur: jalur baca terlalu langsung ke origin, cache tidak dikendalikan, proteksi diterapkan terlalu terlambat, atau observabilitas tidak cukup untuk membedakan lonjakan normal dari scraping terkoordinasi.

Dalam konteks kebocoran daftar pemenang akibat scraping massal, pertanyaan praktisnya bukan “pakai WAF atau tidak”, melainkan lapisan mana yang sebaiknya menahan traffic, kapan konten boleh di-cache, bagaimana memisahkan read path, dan berapa biaya kompleksitas yang layak ditanggung. Artikel ini membahas trade-off empat pendekatan: monolit dengan rate limit, cache/CDN agresif, edge worker/WAF, dan pemisahan read path, beserta kapan masing-masing cukup, kapan perlu kombinasi, dan kapan tim justru sedang overengineering.

Masalah Nyata: Bukan Hanya Bot, Tapi Jalur Rilis yang Terlalu Mudah Ditebak

Pada kasus kebocoran daftar pemenang, pelaku scraping sering tidak perlu “membobol” sistem. Mereka cukup:

  • menebak URL halaman atau ID resource sebelum waktu rilis,
  • mengakses endpoint publik secara berulang dari banyak IP,
  • memanfaatkan cache yang salah konfigurasi,
  • membaca perbedaan respons antara “belum tersedia”, “ada tapi belum dipublikasi”, dan “sudah terbuka”,
  • mengamati perubahan ukuran respons, header, atau waktu proses sebagai side channel.

Karena itu, strategi pencegahan harus dimulai dari prinsip berikut:

  • Jangan expose data yang belum boleh dibaca, walau URL-nya belum dipromosikan.
  • Bedakan publish state dan storage state. Data boleh sudah tersimpan, tetapi jalur baca publik harus tetap menolak.
  • Batasi akses sedini mungkin, idealnya sebelum request mencapai origin.
  • Pastikan cache tidak membocorkan state melalui key, TTL, atau aturan bypass yang salah.
  • Siapkan observabilitas untuk traffic anomali, bukan hanya uptime.

Opsi 1: Monolit dengan Rate Limit

Pendekatan paling sederhana adalah tetap memakai aplikasi monolit sebagai origin utama, lalu menambahkan rate limiting, throttling, dan validasi state publish pada endpoint sensitif. Ini sering cukup untuk tim kecil atau sistem yang belum benar-benar berada di bawah serangan scraping terdistribusi.

Kapan pendekatan ini cukup

  • Traffic tinggi tetapi pola akses masih cukup terkonsentrasi.
  • Tim infra kecil dan deployment harus tetap sederhana.
  • Data sensitif hanya ada di beberapa endpoint yang bisa dilindungi ketat.
  • Belum ada kebutuhan global edge enforcement yang kompleks.

Kenapa bekerja

Rate limiting di level aplikasi efektif untuk menahan pelaku yang memakai satu identitas teknis secara berulang: satu IP, satu token, satu session, atau satu fingerprint ringan. Monolit juga memudahkan implementasi aturan bisnis yang benar-benar tahu status data: misalnya hasil undian sudah tersimpan di database, tetapi endpoint tetap mengembalikan 404 atau 403 sampai waktu publikasi tiba.

Contoh implementasi sederhana

# pseudo-config rate limit per route sensitif
# prinsip: endpoint publik umum longgar, endpoint hasil sangat ketat

GET /announcement/:id
  limit by ip = 30 requests / minute
  burst = small

GET /winners/:batchId
  limit by ip = 5 requests / minute
  limit by user-agent fingerprint = 10 requests / minute
  if publish_at > now then return 404
  if suspicious score high then return 429

Yang penting di sini bukan angka spesifiknya, melainkan pemisahan kelas endpoint. Kesalahan umum adalah memberi limit seragam untuk semua route, sehingga endpoint statis dan endpoint sensitif diperlakukan sama.

Kelebihan

  • Biaya operasional rendah jika stack sudah ada.
  • Maintainability tinggi untuk tim kecil karena logika tetap terpusat.
  • Debugging relatif mudah karena request dan keputusan proteksi ada di tempat yang sama.
  • Aturan bisnis akurat karena aplikasi tahu state data sebenarnya.

Kekurangan

  • Latensi dan beban origin tetap tinggi karena request jahat sudah telanjur masuk ke aplikasi.
  • Kurang efektif terhadap scraping terdistribusi dari banyak IP/ASN/region.
  • Rate limit berbasis IP sering false positive pada NAT kantor, kampus, atau jaringan seluler.
  • Observabilitas rawan terlambat jika aplikasi kewalahan sebelum sinyal scraping terlihat jelas.

Kesalahan umum

  • Mengembalikan kode status berbeda untuk “tidak ada” vs “belum dipublikasi”, sehingga scraper bisa menguji state.
  • Menaruh data sensitif di response internal lalu disembunyikan hanya di frontend.
  • Rate limit hanya di API, tetapi halaman HTML tetap merender data dari backend yang sama.
  • Tidak memisahkan limit berdasarkan route sensitif.

Opsi 2: Cache/CDN Agresif

Jika beban baca sangat tinggi, cache/CDN agresif bisa menjadi lapisan utama untuk mengurangi akses langsung ke origin. Namun untuk mencegah scraping massal, cache bukan proteksi otomatis. Cache berguna jika dipakai untuk menyusutkan permukaan origin dan mengendalikan kapan konten benar-benar tersedia.

Kapan cocok

  • Mayoritas traffic adalah read-heavy dan kontennya sama untuk banyak pengguna.
  • Lonjakan traffic saat rilis sangat tinggi dan dapat diprediksi.
  • Tujuan utama adalah menahan load origin sekaligus menjaga latensi tetap rendah.

Kenapa bekerja

Cache/CDN mengurangi jumlah request yang sampai ke aplikasi dan database. Jika halaman publik aman untuk di-cache setelah waktu rilis, origin tidak perlu memproses semua permintaan. Ini sangat membantu saat halaman pengumuman dibuka serentak oleh pengguna sah.

Tetapi ada syarat penting: jangan cache konten sensitif sebelum benar-benar boleh dipublikasikan. Bila cache diisi terlalu cepat, Anda hanya memindahkan kebocoran dari database ke edge node.

Pola cache yang aman untuk halaman hasil

  • Sebelum waktu rilis: origin selalu mengembalikan respons generik, misalnya 404 atau 403 tanpa metadata yang membocorkan state.
  • Setelah waktu rilis: cacheable response dibuka dengan TTL yang sesuai.
  • Invalidate cache secara eksplisit saat status berubah penting, jangan hanya menunggu TTL jika momen rilis harus presisi.
# ilustrasi header, bukan spesifikasi vendor tertentu
# sebelum publish
Cache-Control: no-store

# sesudah publish, untuk halaman publik yang aman di-cache
Cache-Control: public, max-age=60, stale-while-revalidate=30

Kelebihan

  • Latensi rendah untuk user publik.
  • Beban origin turun drastis pada jalur baca.
  • Biaya per request ke aplikasi dan database bisa menurun bila cache hit tinggi.
  • Skalabilitas baca lebih sederhana dibanding menambah banyak replika aplikasi tanpa strategi cache.

Kekurangan

  • Salah konfigurasi bisa menyebabkan kebocoran lebih cepat dan lebih luas.
  • Cache invalidation tetap sulit, terutama untuk rilis terjadwal yang harus akurat.
  • Debugging lebih rumit karena perilaku berbeda antara edge, CDN, dan origin.
  • Observabilitas harus mencakup cache hit/miss, bukan hanya log aplikasi.

Kesalahan umum

  • Meng-cache response yang berbeda berdasarkan cookie, header, atau status publish tanpa key yang benar.
  • Menganggap “URL belum diketahui publik” sebagai proteksi.
  • Mengandalkan TTL panjang untuk konten yang sebenarnya berubah tepat saat waktu rilis.
  • Mengirim halaman HTML aman, tetapi asset JSON pendukung tetap dapat diakses langsung sebelum waktunya.

Opsi 3: Edge Worker atau WAF

Edge worker dan WAF berguna saat Anda perlu memblokir, menantang, atau menilai traffic sebelum menyentuh origin. Ini biasanya langkah berikutnya ketika rate limit di monolit mulai tidak cukup, atau ketika beban dan pola serangan sudah terlalu terdistribusi.

Kapan cocok

  • Traffic datang dari banyak region dan banyak IP yang berubah cepat.
  • Anda perlu proteksi sebelum origin menerima request.
  • Tim sudah siap mengelola aturan, observabilitas edge, dan proses tuning false positive.

Kenapa bekerja

Layer edge dapat menerapkan aturan berdasarkan sinyal yang lebih dekat ke perimeter: reputasi IP, volume per ASN, pola request, header anomali, frekuensi probing path, atau challenge adaptif. Request yang jelas-jelas mencurigakan bisa dipotong jauh lebih awal, sehingga origin dan database tetap stabil.

Contoh logika edge yang masuk akal

// pseudo-code edge worker
if (request.path.startsWith('/winners')) {
  if (now < publishTime) {
    return genericNotFound();
  }

  if (isKnownBadIp(request) || requestRateTooHigh(request)) {
    return tooManyRequests();
  }

  if (looksAutomated(request) && riskScore(request) > threshold) {
    return challengeOrBlock();
  }
}

return fetchOrigin(request);

Poin terpenting: edge worker bukan pengganti kontrol bisnis di origin. Jika edge salah bypass, origin tetap harus menolak data yang belum publish.

Kelebihan

  • Mengurangi load origin secara signifikan karena request jahat dihentikan lebih awal.
  • Latensi keputusan proteksi rendah karena terjadi dekat pengguna.
  • Fleksibel untuk challenge, denylist/allowlist, geo rule, atau proteksi per path.
  • Cocok untuk serangan scraping terdistribusi yang sulit ditangani murni di aplikasi.

Kekurangan

  • Kompleksitas deployment meningkat karena ada logika di luar aplikasi utama.
  • False positive lebih berbahaya jika aturan terlalu agresif, misalnya memblokir traffic kampus, kantor besar, atau crawler sah.
  • Observabilitas terfragmentasi antara edge, CDN, WAF, dan origin.
  • Maintainability menurun bila aturan tumbuh tanpa versioning dan review yang baik.

Debugging tip

  • Simpan reason code untuk setiap block/challenge agar tim support tahu kenapa user ditolak.
  • Tambahkan mode log-only sebelum enforcement penuh untuk aturan baru.
  • Buat dashboard per path sensitif: volume, challenge rate, block rate, error origin, cache hit rate.
  • Pastikan ada prosedur bypass sementara untuk incident response.

Opsi 4: Pemisahan Read Path

Pemisahan read path berarti jalur baca publik dipisah dari jalur tulis atau jalur administrasi, baik secara service, database replica, materialized view, indeks pencarian, maupun publikasi snapshot statis. Ini bukan sekadar optimasi performa; ini cara kuat untuk mengecilkan peluang kebocoran state internal ke endpoint publik.

Kapan perlu

  • Sistem punya domain data yang sensitif terhadap waktu rilis.
  • Query baca publik sangat berbeda dari query aplikasi internal/admin.
  • Tim sudah cukup matang untuk mengelola sinkronisasi, pipeline publikasi, dan debugging lintas komponen.

Kenapa bekerja

Dengan memisahkan read path, endpoint publik hanya melihat data yang memang sudah diekspor ke kanal publik. Data internal yang masih “tersimpan tapi belum publish” tidak berada di jalur baca publik sama sekali. Ini jauh lebih aman daripada berharap setiap query aplikasi selalu ingat memfilter status publish dengan benar.

Contoh pola implementasi

  • Read model publik: tabel atau indeks khusus yang hanya berisi item terpublikasi.
  • Snapshot statis: pada saat rilis, hasil dipublikasikan sebagai file JSON/HTML statis yang kemudian dilayani CDN.
  • Replica baca terkontrol: service publik membaca dari sumber terpisah dengan skema yang memang dibatasi.
# alur sederhana
Admin System --(prepare winners)--> Internal DB
Publish Job --(at release time)--> Public Read Model / Static JSON
Public Site --> CDN/Edge --> Public Read Model only

Kelebihan

  • Keamanan desain lebih baik karena data non-publik tidak ikut terbaca oleh jalur publik.
  • Performa baca tinggi karena model data bisa dioptimalkan khusus untuk query publik.
  • Lebih mudah di-cache bila output sudah stabil dan bersifat publik.

Kekurangan

  • Kompleksitas sistem naik: sinkronisasi, publish job, rollback, monitoring pipeline.
  • Deployment dan operasional lebih mahal karena komponen bertambah.
  • Risiko inkonsistensi jika pipeline publish gagal atau terlambat.

Anti-pattern yang sering terjadi

  • Membuat banyak service kecil hanya untuk “terlihat modern”, padahal satu monolit dengan model publik terpisah sudah cukup.
  • Memecah read path tanpa definisi ownership yang jelas.
  • Tidak punya prosedur rollback publikasi bila data salah.

Kapan Cukup Satu Opsi, Kapan Harus Dikombinasikan?

Satu opsi saja cukup jika

  • Monolit + rate limit cukup bila data sensitif sedikit, traffic belum terlalu terdistribusi, dan tim kecil butuh perubahan cepat.
  • Cache/CDN agresif cukup bila masalah utama adalah lonjakan pembaca sah setelah waktu rilis, bukan probing sebelum rilis.

Perlu kombinasi jika

  • Monolit + cache/CDN: origin perlu dilindungi dari lonjakan baca, tetapi logika publish state masih paling aman di aplikasi.
  • Monolit + edge/WAF: scraping mulai terdistribusi dan request mencurigakan harus diblokir sebelum origin.
  • Cache/CDN + edge/WAF: situs publik skala besar dengan read-heavy traffic dan pola abuse berulang.
  • Read path terpisah + cache/CDN + edge: data sangat sensitif terhadap waktu rilis, traffic tinggi, dan tim mampu mengelola arsitektur lebih matang.

Matriks Keputusan: Tim Kecil vs Tim Matang

AspekMonolit + Rate LimitCache/CDN AgresifEdge Worker/WAFPemisahan Read Path
Biaya operasionalRendahRendah-menengahMenengahMenengah-tinggi
Kompleksitas deploymentRendahMenengahMenengahTinggi
Latensi userTergantung originSangat baik untuk cache hitBaik, dengan overhead kecil untuk inspeksiBaik jika model baca optimal
Perlindungan sebelum originRendahTerbatasTinggiTergantung kombinasi edge/CDN
Risiko false positiveSedangRendah pada cache, tapi ada risiko cache salahTinggi jika rule agresifRendah pada akses publik, tapi ada risiko publish pipeline
ObservabilitasMudah di appPerlu metrik cachePerlu korelasi multi-layerPerlu monitor pipeline dan data freshness
MaintainabilityBaik untuk tim kecilBaik jika aturan sederhanaBisa menurun tanpa governanceBaik untuk tim matang, berat untuk tim kecil

Rekomendasi praktis:

  • Tim kecil: mulai dari monolit dengan validasi publish state yang ketat, rate limit per route sensitif, lalu tambah cache/CDN untuk halaman publik setelah rilis. Edge/WAF dipakai secukupnya, jangan langsung memindahkan banyak logika bisnis ke edge.
  • Tim matang: kombinasikan edge enforcement, cache/CDN, dan read path terpisah untuk data yang sensitif terhadap waktu. Pastikan ownership, observabilitas, dan runbook insiden sudah jelas.

Checklist Mitigasi Bertahap

  1. Tutup kebocoran state

    Pastikan endpoint publik tidak bisa membedakan “belum publish” dan “tidak ada” dengan sinyal yang mudah discrape.

  2. Kelompokkan endpoint sensitif

    Jangan terapkan rate limit seragam. Tentukan route yang benar-benar rawan scraping.

  3. Tambahkan rate limit di origin

    Gunakan kunci campuran: IP, path, token, atau fingerprint ringan. Siapkan logging alasan throttling.

  4. Pasang cache/CDN untuk jalur baca publik

    Cache hanya setelah data memang boleh dipublikasikan. Audit key, TTL, dan invalidation.

  5. Aktifkan proteksi edge/WAF secara bertahap

    Mulai dengan mode observasi, ukur false positive, baru lanjut ke challenge atau block.

  6. Pisahkan read path jika risiko dan skala menuntut

    Khususnya untuk daftar hasil, ranking, atau pengumuman massal yang sensitif terhadap waktu rilis.

  7. Bangun observabilitas lintas layer

    Kumpulkan metrik: block rate, challenge rate, cache hit ratio, origin error rate, DB load, dan latency per path.

  8. Siapkan runbook insiden

    Termasuk rollback rule edge, purge cache, switch ke mode static, dan komunikasi internal.

Skenario Insiden dan Respons yang Masuk Akal

Skenario 1: Probing sebelum waktu rilis

Gejala: banyak request ke path hasil dengan variasi ID, mayoritas 404, dari banyak IP berbeda.

Respons:

  • Pastikan origin mengembalikan respons generik yang konsisten.
  • Naikkan proteksi edge untuk path tersebut.
  • Tambahkan deteksi pola enumeration pada parameter/ID.
  • Audit apakah asset JSON atau endpoint pendukung masih terbuka.

Skenario 2: Lonjakan pembaca sah saat rilis

Gejala: tidak ada pola scraping menonjol, tetapi origin dan DB CPU naik tajam setelah pengumuman dibuka.

Respons:

  • Alihkan sebanyak mungkin traffic ke cache/CDN.
  • Kurangi kerja sinkron di origin untuk halaman publik.
  • Jika memungkinkan, sajikan snapshot statis hasil rilis.

Skenario 3: WAF terlalu agresif

Gejala: user sah dari kampus atau operator seluler tertentu gagal mengakses halaman hasil.

Respons:

  • Tinjau rule berdasarkan ASN, geo, atau challenge threshold.
  • Gunakan log-only mode untuk rule baru sebelum enforcement penuh.
  • Sediakan bypass sementara dan pantau dampaknya.

Skenario 4: Data ter-publish di origin sebelum semestinya

Gejala: halaman atau JSON tertentu bisa diakses sebelum pengumuman resmi, walau link belum terlihat di UI.

Respons:

  • Anggap ini bug kontrol akses atau publish gating, bukan sekadar masalah scraping.
  • Pindahkan logika publish state ke lapisan yang lebih kuat dan eksplisit.
  • Pertimbangkan read path publik terpisah agar data non-publik tidak berada di jalur baca publik.

Tanda-Tanda Overengineering

Tidak semua situs publik perlu edge script kompleks, banyak service, dan pipeline publish bertingkat. Anda mungkin sedang overengineering jika:

  • Traffic aktual belum menunjukkan pola abuse yang memerlukan edge logic khusus.
  • Tim belum punya observabilitas dasar, tetapi sudah menambah banyak lapisan proteksi.
  • Aturan WAF sulit dipahami bahkan oleh tim sendiri.
  • Read path dipisah menjadi banyak service tanpa kebutuhan domain yang jelas.
  • Biaya debugging dan on-call naik lebih cepat daripada penurunan risiko.

Prinsip praktisnya: naikkan kompleksitas hanya setelah bottleneck dan pola ancaman benar-benar terlihat. Untuk banyak tim, urutan yang sehat adalah: perbaiki publish gating di aplikasi, tambahkan rate limit terarah, cache jalur publik yang aman, lalu gunakan edge/WAF untuk memotong traffic anomali. Pemisahan read path dilakukan ketika sensitivitas data dan skala sistem memang membenarkannya.

Penutup

Untuk mencegah scraping massal pada situs publik bertraffic tinggi, pertanyaan utamanya bukan memilih satu teknologi yang “paling aman”, melainkan menempatkan kontrol di lapisan yang tepat. Monolit dengan rate limit unggul dalam kesederhanaan dan akurasi aturan bisnis. Cache/CDN agresif unggul untuk menahan lonjakan baca dan menurunkan latensi. Edge worker/WAF unggul untuk memblokir scraping sebelum origin. Pemisahan read path unggul ketika data sensitif terhadap waktu rilis dan jalur publik harus benar-benar steril dari state internal.

Jika Anda mengelola halaman pengumuman, daftar pemenang, atau hasil seleksi, langkah paling penting adalah memastikan data yang belum boleh dibuka memang tidak tersedia di jalur baca publik. Setelah itu, baru pilih kombinasi arsitektur yang seimbang antara biaya, kompleksitas, latensi, false positive, observabilitas, dan maintainability.