kekavigi.xyz

Terpaksa Belajar Membuat Bom

Ini baru gestur jari tengah, belum mengepalkan tangan, maupun mengayunkannya ke muka.

Ditulis tanggal oleh A. Keyka Vigiliant. Konten diterbitkan dibawah lisensi CC BY-SA 4.0.


Hmm... entah bagaimana cara memulai tulisan ini. Oke, mungkin ini lebih baik. Anda membaca blog saya; kebanyakan isinya adalah diari yang ditulis dengan kurang jelas. Ya, saya mengatakan itu dengan ukuran standar saya. Walau saya berusaha menulis sebaik mungkin, dengan argumen-argumen yang masuk akal, dan tidak ada pernyataan yang salah, sebagian dari isi pikiran saya menganggap ini adalah sekadar hobi; tidak perlu serius seperti dulu saya menulis skripsi. Akibatnya, saya tidak mengharapkan tulisan di blog ini (mau) dibaca orang. Bahkan sejak tahun 2016 lalu. Jika ternyata ada yang (mau) membaca, terima kasih! Saya tidak menyangka hal itu, dan... maaf jika gaya menulis saya agak berbeda-beda antar postingan.

Blog ini adalah pojok terpencil di Internet, tempat saya menulis, sunyi, dan itu semua terasa nyaman bagi saya. Namun Negara Api datang menyerang.

Sekitar setahun lalu, saya pindah ke dari Github Pages ke Cloudflare untuk mengurus blog ini. Ada banyak pro-kontra di pikiran saya memilih (dan tetap menggunakan) Cloudflare, tapi yah... itu adalah opsi yang cocok untuk saya saat itu (dan sekarang). Sialnya, fitur di Cloudflare yang saya kurang sukai adalah penyebab saya mengetahui seberapa gilanya kejadian yang menimpa blog ini. Begitu gilanya, sampai saya merasa perlu berterima kasih pada Cloudflare (yang selanjutnya saya singkat CF) punya fitur ini. Untuk bisa tidak menyukai sekaligus berterima kasih? Wow, itu olahraga mental yang melelahkan.

Mari saya jelaskan maksud saya tadi. Saya kurang menyukai aktivitas logging (pencatatan) kunjungan situs. Saya saat ini bahkan merasa bimbang, jikalau alasan saya melakukan logging sebenarnya cuma untuk mengejar suatu metrik yang tak berarti (dalam konteks tujuan saya menulis di blog ini). Tapi CF? CF terasa seperti mencatat semuanya; saya cuma tidak bisa mengakses semuanya itu karena akun saya ada di versi gratisan. Awalnya, yang tercatat di log adalah semua kunjungan yang saya lakukan. Namun entah sejak kapan, CF selalu mencatat ada lebih dari dua ribu pengunjung unik blog ini setiap bulannya. Ini omong kosong, lebih kosong daripada apa yang fisika kuantum perbolehkan. Siapa saya, sampai ada dua ribu manusia berbeda sudi mengunjungi situs saya?

Di halaman Analytics di menu Security, Cloudflare menampilkan maksimal seratus sampel log kunjungan situs. Walaupun hanya sampel, dan hanya seratus log yang bisa saya lihat, saya tidak dapat menahan diri, untuk tidak berprasangka siapa biang kerok kegilaan ini. Sebagian besar adalah crawler, yang menguji semua jalur URL WordPress yang mungkin memiliki celah keamanan (contohnya /xmlrpc.php dan yang berawalan /wp-content/plugins/). Sisanya adalah scraper (pengais) yang secara presisi membaca semua tulisan saya. Oh itu jelas bot: tidak ada ada manusia normal yang bisa membuka semua halaman di situs saya dalam waktu kurang dua detik. Jikalau ada, untuk apa? Saya ingin berkata saya merasa risih, tapi dua ribu kunjungan per bulan? siapapun mereka, tindakan itu terlalu beringas.

Saya sudah mencoba solusi-solusi yang ditawarkan CF, seperti Bot Fight Mode, Block AI Bot, dan beragam kombinasi Rules yang bisa saya pikirkan. Namun saya melihat itu tidak efektif. Bot tetap membabi buta, dan (tergantung rule yang dibuat), saya malah dianggap bot oleh CF (dan butuh waktu lama untuk CF menyadari saya manusia).

Ya, mungkin mustahil mencegah bot mengunjungi situs, tetapi tidak ada salahnya mengacungkan jari tengah selagi mereka melakukannya.

Saat ini ada banyak proyek untuk menjawab masalah bot (khususnya yang mengais konten), beberapa diantaranya adalah iocaine, Nephentes, dan Quixotic (yang mungkin cocok untuk situs statis seperti blog saya). Itu keren, tapi saya masih ragu untuk menyertakan tulisan yang secara matematis lebih buruk daripada tulisan saya, ke blog ini. Lalu saya bertemu dengan tulisan I use Zip Bombs to Protect my Server oleh Ibrahim Diallo. Idenya sederhana: Anda mungkin pernah mengompres (beberapa) berkas dokumen, atau gambar, atau apapun itu menjadi satu berkas .zip (atau .rar, .7z, dst.) yang ukurannya lebih kecil. Nah, kita juga bisa merancang berkas .zip khusus yang ukurannya kecil, disebut compression bomb, yang ketika di-dekompres akan menghasilkan sesuatu yang sangat besar; program apapun yang mencoba men-dekompres-nya akan melakukan seppuku digital. Lebih tepatnya program yang tidak menyangka ada yang tega memberi mereka compression bomb. Oke, ini terasa seperti ide yang keren untuk dicoba: membuat bom yang tidak disangka oleh para pengais.

Hal yang selanjutnya saya tulis disini adalah iterasi pertama bom ini. Saya belum mengecek dampaknya pada perangkat (sistem? program?) pengais seperti crawlee, scrapy, dan sebagainya. Saya hanya bisa melihat bom ini bisa membuat peramban (browser) menjadi tidak responsif.

Kode yang digunakan oleh Ibrahim untuk membuat dan menyajikan bom keren. Namun saya melihat beberapa hal yang membuat bom sulit diendus. Pertama, menambahkan metadata Content-Type dengan nilai text/html; charset=utf-8. Lalu, ada baiknya kita menjaga agar ukuran bom kurang dari satu-dua megabita (berkas HTML berukuran lebih dari itu tidak umum dijumpai). Selain itu, tidak ada salahnya membuat bom dengan teknik kompresi lainnya yang umum digunakan untuk mengompres berkas HTML, seperti brotli dan zstd. Karena saya tidak yakin efektivitas bom yang dibuat dengan menggunakan dd if=/dev/zero, saya mengubah cara membuat bom menjadi berikut

yes "4" | tr -d "\n" | dd bs=1k conv=notrunc iflag=fullblock count=$((1*1024*1024)) | gzip --best -c | base64 -w0 > bomb.gz.base64;

(untuk brotli dan zstd yang memiliki kemampuan kompresi yang lebih baik, saya meningkatkan count menjadi 40*1024*1024 dan 10*1024*1024). Isi dari berkas bomb.gz.base64 (dan sejenisnya untuk teknik kompresi lainnya), saya salin ke kode Javascript berikut:

export function onRequest(context) {
  const encHeader = context.request.headers.get("accept-encoding") || "";

  if (encHeader.includes("zstd")) {
    return serveCompressed(zstdDataBase64, "zstd");
  } else if (encHeader.includes("br")) {
    return serveCompressed(brotliDataBase64, "br");
  } else if (encHeader.includes("gzip")) {
    return serveCompressed(gzipDataBase64, "gzip");
  } else {
    return new Response("Raw version not available", { status: 406 });
  }
}

function serveCompressed(base64Data, encoding) {
  const binaryData = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));

  return new Response(binaryData, {
    encodeBody: "manual",
    headers: {
      "Content-Type": "text/html; charset=utf-8",
      "Content-Encoding": encoding,
      "Cache-Control": "no-transform",
    },
  });
  // oh... juga pastikan tidak ada rule di pengaturan CF situs Anda,
  // yang mengompres dan/atau menyinggah halaman hasil function ini 
}

const zstdDataBase64 = "KLUv/QRYVAAAEDQ0AQD7/znAAgIAEDQCABA0AgAQNAIAEDQCABA0AgAQN...";
const brotliDataBase64 = "z///f/glaOKxQCD3/p/////wSwDEYQGA7v0/////4ZcAiMMiAN37f/7...";
const gzipDataBase64 = "H4sIAAAAAAACA+zBgQAAAACAIKn92RapCgAAAAAAAAAAAAAAAAAAAAAAA...";

Berkas Javascript ini selanjutnya saya simpan di /functions/hello.js, seperti dokumentasi Functions-nya Couldflare Pages. Hasil dari fungsi ini dapat dilihat di kekavigi.xyz/hello. Setelah bom dibuat, saya membuat Rewrite Rule yang memetakan semua URL yang berakhiran .php, atau yang mengandung kata wp, ke halaman bom. Ada juga opsi untuk memetakan berdasarkan AS Number, Hostname, User Agent, dll., tapi saya ragu tingkat efektivitasnya; mengingat sifat pengais seperti virus/bakteri, akan selalu berubah mengakali kondisi lingkungan.

Satu pengalaman yang saya ingin bagikan, Cloudflare sulit ditebak. Terkadang metadata Content-Length akan disertakan di header respon HTTP, tanpa perlu ditulis di kode JS. Sebaliknya, terkadang metadata tersebut dihapus walau secara eksplisit ditulis di kode. Begitu pula dengan metadata Content-Encoding. Baiklah, selama mengunduh halaman menggunakan curl atau mengakses halaman lewat peramban akan "mengaktifkan" bom, terserah kamu Cloudflare. Saya belum menutup kemungkinan penyebab respon yang flaky ini adalah skill-issue kemampuan Javascript diri saya.

Nantinya, saya akan "menanam" pranala-pranala ke halaman bom di keseluruhan blog ini. Ditanam sedemikian sehingga tidak terlihat -- menggunakan CSS -- oleh pembaca; hanya oleh pengais yang rakus. Apakah bom ini efektif? Jika suatu saat saya kembali menulis tentang mempertahankan blog dari pengais, kemungkinan besar jawabannya tidak. Ketika itu terjadi, saya akan teringat foto suatu bendera, bertuliskan We do this not because it is easy, but because we thought it would be easy.