Belajar Menguji Business Logic:
Dari Alur Normal hingga Bukti.
Pengalaman menyusun cara berpikir yang lebih terarah untuk memahami aturan bisnis, menguji satu perubahan, dan memastikan dampak melalui data utama di server.
Materi ini ditujukan untuk edukasi dan pengujian pada sistem milik sendiri atau sistem yang telah memberikan izin tertulis. Contoh dibuat generik dan tidak menyatakan kerentanan pada organisasi tertentu.
Ketika pertama mempelajari business logic vulnerability, saya mengira tantangan utamanya adalah menemukan payload yang tepat. Setelah lebih banyak membaca, menyusun eksperimen, dan meninjau kembali hasil pengujian, saya menyadari bahwa bagian tersulit justru memahami cara sebuah bisnis mengambil keputusan. Server dapat menerima request yang bentuknya valid, tetapi hasilnya tetap salah jika aturan harga, kepemilikan, urutan proses, atau batas penggunaan tidak ditegakkan dengan konsisten.
Catatan ini merangkum pendekatan yang saya gunakan saat menyusun materi Business Logic Vulnerabilities - Edisi Menengah/Lanjutan. Tujuannya bukan memberikan jalan pintas untuk menyebut perilaku aneh sebagai celah. Tujuannya adalah membantu peneliti membangun pertanyaan yang sempit, mengujinya secara terkontrol, dan berani menutup dugaan ketika data utama menunjukkan bahwa sistem tetap bekerja sebagaimana mestinya.
Mengapa business logic berbeda?
Masalah teknis seperti versi komponen lama atau konfigurasi header sering memiliki pola yang dapat dikenali alat otomatis. Business logic bergantung pada konteks yang jauh lebih spesifik. Diskon mungkin sah untuk pengguna baru, tetapi tidak untuk akun lama. Refund mungkin sah setelah pembayaran, tetapi tidak boleh melebihi nilai transaksi. Seorang administrator mungkin boleh mengubah konfigurasi proyek A, tetapi tidak otomatis boleh mengubah proyek B.
Karena itu, respons sukses saja tidak cukup. HTTP 200 dapat berarti request diterima, sementara saldo, stok, status pesanan, atau hak akses tetap tidak berubah. Sebaliknya, respons error juga belum tentu menutup seluruh pertanyaan jika operasi yang sama tersedia melalui API versi lama, aplikasi mobile, worker, atau alur lain. Kesimpulan harus mengikuti keputusan server dan state yang benar-benar tersimpan.
Mulai dari alur normal
Sebelum mengubah parameter, saya menuliskan alur yang seharusnya berhasil. Pada checkout sederhana, misalnya, pengguna menambahkan produk, memakai kupon yang memenuhi syarat, memilih metode pembayaran, menyelesaikan pembayaran, lalu pesanan diproses. Setiap langkah mempunyai prasyarat dan menghasilkan state baru. Jika alur normal belum dipahami, perubahan yang dilakukan akan sulit dinilai karena kita tidak memiliki pembanding yang stabil.
Alur normal juga membantu menemukan titik keputusan. Siapa yang menghitung harga akhir? Kapan kupon ditandai sudah digunakan? Apakah status pembayaran berasal dari browser, backend, atau penyedia pembayaran? Di mana stok dikurangi? Jawaban atas pertanyaan tersebut menunjukkan data mana yang harus dibaca kembali setelah eksperimen.
Lima tahap untuk menguji keputusan bisnis
Setiap tahap mempersempit dugaan sampai hasil dapat dibuktikan atau ditutup secara jelas.
Jalankan fitur secara normal dan catat perubahan state.
Tentukan aktor, objek, operasi, nilai, waktu, dan batas penggunaan.
Ganti hanya satu parameter, urutan, role, atau kondisi.
Gunakan baseline dan kontrol pembanding yang hasilnya telah diketahui.
Periksa ledger, stok, kepemilikan, atau status utama di server.
Tulis aturan sebelum menguji
Saya menggunakan bentuk pertanyaan yang sederhana: aktor mana boleh melakukan tindakan apa, terhadap objek mana, dalam state dan waktu apa? Untuk transaksi, pertanyaan tersebut perlu ditambah nilai, mata uang, frekuensi, metode pembayaran, serta kondisi refund. Rumusan ini membuat pengujian lebih terarah daripada mencoba banyak input tanpa alasan yang jelas.
Contohnya, aturan sebuah kupon bukan sekadar "kode ini valid". Aturannya mungkin berbunyi: pengguna baru boleh memakai kupon satu kali, hanya untuk produk tertentu, sebelum tanggal kedaluwarsa, dengan nilai transaksi minimum, dan kupon tetap dianggap terpakai setelah pesanan dibuat. Semakin jelas aturan tersebut, semakin mudah menyusun eksperimen yang dapat dibantah.
Baseline, satu perubahan, dan kontrol pembanding
Baseline adalah request normal yang berhasil dan menghasilkan state yang dapat diperiksa. Setelah baseline stabil, saya mengubah satu variabel. Jika ingin menilai kepemilikan objek, hanya identifier objek yang diganti sementara session, method, body lain, dan urutan tetap sama. Jika ingin menilai batas nilai, hanya jumlah yang diubah. Cara ini membantu menunjukkan bagian mana yang benar-benar memengaruhi keputusan server.
Kontrol pembanding sama pentingnya. Misalnya, setelah kupon digunakan pada pesanan pertama, penggunaan ulang pada pesanan kedua seharusnya ditolak. Jika eksperimen setelah pembatalan justru diterima, jalankan kembali penggunaan pada kondisi tanpa pembatalan. Bila kondisi tanpa pembatalan tetap ditolak, perbedaan tersebut memperkuat dugaan bahwa transisi pembatalan memengaruhi status kupon. Jika keduanya diterima, penjelasannya mungkin bukan pembatalan, melainkan aturan kupon memang memperbolehkan penggunaan berulang.
Satu respons yang berbeda adalah sinyal. Kesimpulan baru kuat ketika perbedaan tersebut berulang, penjelasan lain telah diuji, dan state utama menunjukkan aturan bisnis benar-benar gagal.
Lima dimensi yang sering membuka pertanyaan
1. Identity dan ownership
Apakah server memeriksa bahwa objek benar-benar milik aktor? Pemeriksaan tidak berhenti pada token yang valid. Hubungan pengguna dengan order, invoice, workspace, atau parent object harus ikut ditegakkan pada setiap operasi.
2. Value
Harga, jumlah, diskon, refund, saldo, dan mata uang seharusnya dihitung atau diverifikasi oleh server. Nilai dari client dapat menjadi input, tetapi tidak boleh menjadi kebenaran akhir ketika menentukan uang atau hak pengguna.
3. State dan urutan
Fitur memiliki urutan yang diharapkan. Artikel harus disetujui sebelum diterbitkan, pembayaran harus dikonfirmasi sebelum pesanan diproses, dan barang biasanya harus diterima sebelum refund tertentu diberikan. Endpoint langsung, perubahan status, atau penggunaan API lama dapat menguji apakah urutan tersebut benar-benar ditegakkan.
4. Time dan lifecycle
Token kedaluwarsa, undangan dicabut, kupon berakhir, pesanan dibatalkan, dan akun dihapus adalah perubahan keamanan yang berbeda. Pengujian perlu membaca perilaku sebelum serta sesudah transisi, termasuk setelah jeda yang wajar jika cache atau worker terlibat.
5. Frequency dan concurrency
Operasi satu kali dapat gagal ketika dua request diproses hampir bersamaan. Pengujian concurrency harus dibatasi pada akun dan objek uji, jumlah request minimal, serta state yang dapat dipulihkan. Targetnya bukan membebani layanan, tetapi menilai apakah pemeriksaan dan perubahan data dilakukan secara atomik.
Contoh: kupon setelah pembatalan
Bayangkan kupon hanya boleh digunakan satu kali per pengguna. Baseline-nya adalah membuat cart uji, memakai kupon, melakukan checkout, lalu membaca profil kupon atau riwayat benefit untuk memastikan statusnya menjadi terpakai. Eksperimen berikutnya membatalkan pesanan dengan alur resmi, membuat cart baru, dan mencoba kupon yang sama.
Jika API mengembalikan sukses, pekerjaan belum selesai. Periksa apakah diskon benar-benar masuk ke total pesanan baru. Baca status kupon pada sumber data utama. Ulangi alur dengan objek uji baru. Jalankan kontrol pembanding tanpa pembatalan. Hanya jika diskon diterapkan berulang, state kupon tidak konsisten, hasil dapat direproduksi, dan aturan produk memang menyatakan satu kali penggunaan, barulah ada bukti kegagalan aturan bisnis.
Contoh tersebut juga memperlihatkan pentingnya menghentikan eksperimen pada dampak minimum yang cukup. Tidak perlu membuat banyak pesanan atau memperbesar nilai diskon. Satu objek uji, satu penggunaan tambahan yang terverifikasi, dan cleanup yang jelas sudah cukup untuk menunjukkan mekanismenya.
Kesalahan yang pernah saya temui saat belajar
- Menganggap HTTP 200 sebagai bukti akhir. Respons harus dibandingkan dengan total pesanan, saldo, ledger, stok, atau status yang tersimpan.
- Mengubah banyak variabel sekaligus. Hasil menjadi sulit dijelaskan karena tidak diketahui perubahan mana yang menentukan keputusan.
- Menggunakan daftar payload tanpa model aturan. Banyak request dapat terkirim, tetapi sedikit informasi yang benar-benar diperoleh.
- Menaikkan klaim terlalu cepat. Perilaku menarik belum tentu pelanggaran keamanan; bisa jadi aturan produk memang mengizinkannya.
- Melupakan cleanup. Akun, cart, pesanan, undangan, atau konfigurasi uji harus dikembalikan atau dicatat untuk dihapus.
- Menutup seluruh fitur karena satu uji gagal. Hasil negatif hanya menjawab kombinasi aktor, objek, state, endpoint, dan kondisi yang benar-benar diuji.
Membedakan sinyal, bukti, dan dampak
Saya membagi hasil menjadi beberapa lapisan. Perbedaan respons membuktikan bahwa server memperlakukan request secara berbeda. Konten yang diterima menunjukkan apa yang berhasil diperoleh. Perubahan state menunjukkan operasi benar-benar diproses. Pelanggaran aturan menunjukkan aktor melakukan sesuatu yang seharusnya dilarang. Dampak menjelaskan konsekuensi nyata, misalnya diskon dipakai dua kali, pengguna membaca order milik akun uji lain, atau status publikasi berubah tanpa persetujuan.
Pemisahan ini membantu menjaga bahasa laporan tetap jujur. Sebuah bypass pada status HTTP dapat dicatat sebagai keberhasilan teknis yang sempit, tetapi belum otomatis menjadi akses tanpa izin. Sebaliknya, hasil negatif juga bernilai karena menutup satu penjelasan dan mencegah kita mengulang pengujian yang sama.
Pelajaran utama dari penyusunan materi
Semakin lama saya mempelajari business logic, semakin saya melihat bahwa kualitas pengujian ditentukan oleh kualitas pertanyaan. Payload hanyalah alat untuk menjawab pertanyaan tersebut. Yang lebih penting adalah memahami aturan bisnis, memilih perubahan dengan informasi tinggi, menyiapkan hasil pembanding, dan menentukan sumber data yang dapat mengonfirmasi hasil.
Pendekatan ini juga membuat komunikasi dengan developer dan pemilik bisnis lebih mudah. Alih-alih menyampaikan bahwa sebuah parameter "terlihat berbahaya", kita dapat menjelaskan aturan yang seharusnya berlaku, kondisi yang diuji, state sebelum dan sesudah, hasil pembanding, serta perbaikan yang paling dekat dengan akar masalah.
Checklist singkat sebelum menyimpulkan
- Apakah scope dan izin pengujian sudah jelas?
- Apakah alur normal berhasil dan terdokumentasi?
- Apakah aturan aktor, objek, operasi, state, nilai, waktu, dan frekuensi sudah ditulis?
- Apakah hanya satu variabel yang berubah?
- Apakah tersedia kontrol pembanding yang tepat?
- Apakah hasil dapat diulang pada objek uji?
- Apakah dampak terlihat pada data utama server?
- Apakah penjelasan yang wajar sudah diperiksa?
- Apakah objek uji dapat dibersihkan?
Artikel ini adalah bagian dari proses belajar yang masih terus berkembang. Saya membagikannya agar diskusi mengenai business logic tidak berhenti pada kumpulan payload, tetapi bergerak menuju eksperimen yang lebih terukur, aman, dan dapat dipertanggungjawabkan.