Keamanan aplikasi web sering diajarkan sebagai daftar kerentanan yang harus dihafal. Pendekatan itu cepat kedaluwarsa karena aplikasi dan teknik penyerangannya terus berubah. Topik ini membangun dasar yang lebih tahan lama, yaitu pola pikir penyerang: kebiasaan menelaah setiap fitur dari sudut orang yang mencari celah, bukan hanya dari sudut pengguna yang berperilaku baik. Setelah topik ini selesai, konsep batas kepercayaan, asumsi tersembunyi, dan kasus penyalahgunaan dapat digunakan untuk menelaah sebuah fitur sederhana dan menemukan celahnya sebelum perbaikan dirancang.
Batas kepercayaan#
Batas kepercayaan (trust boundary) adalah pemisah antara dua wilayah yang tingkat kepercayaannya berbeda. Aplikasi web yang lazim terdiri atas beberapa wilayah sekaligus, yaitu browser di sisi pengguna, jaringan publik di antaranya, server aplikasi, dan basis data. Tingkat kepercayaan berubah setiap kali data menyeberangi wilayah, sehingga aturan dasarnya sederhana: data yang baru tiba dari wilayah lain selalu diperlakukan sebagai masukan (input) yang belum dipercaya.
Diagram berikut memetakan batas kepercayaan pada susunan tersebut.
Kesalahan yang paling sering muncul adalah menganggap data dari aplikasi klien sendiri lebih dapat dipercaya daripada data dari pihak asing. Anggapan itu keliru karena browser berada pada wilayah yang sepenuhnya dikuasai penggunanya: alat pengembang, proxy, dan skrip sederhana memungkinkan setiap permintaan (request) ditulis ulang sebelum dikirim. Kategori A01 Broken Access Control pada OWASP Top 10:2025 sering berakar pada keputusan yang diambil di sisi yang salah dari batas kepercayaan, misalnya pemeriksaan hak akses yang disandarkan pada data dari browser. Keputusan yang menentukan tetap harus diambil di sisi server, setelah data menyeberang.
Asumsi tersembunyi#
Asumsi tersembunyi adalah keyakinan tentang masukan atau perilaku pengguna yang memengaruhi perilaku aplikasi tanpa pernah diperiksa secara eksplisit. Asumsi jarang tertulis karena terasa jelas bagi penulisnya, misalnya anggapan bahwa formulir selalu dikirim melalui halaman yang disediakan. Penyerang justru bekerja dengan melewati halaman itu, sehingga setiap asumsi yang tidak diverifikasi menjadi pintu masuk. Tabel berikut memuat asumsi yang paling sering tertanam dalam kode beserta kenyataannya.
| Asumsi yang tertanam | Kenyataan yang mungkin terjadi |
|---|---|
| Validasi JavaScript pada browser sudah menolak nilai yang tidak wajar | Permintaan dapat dibangun ulang tanpa browser, misalnya dengan curl, sehingga validasi sisi klien terlewati sama sekali |
| Bidang formulir tersembunyi tidak dapat diubah | Nilainya terbaca pada sumber halaman dan bebas disunting sebelum permintaan dikirim |
| Permintaan hanya datang dari aplikasi sendiri | Proxy memungkinkan permintaan apa pun disusun secara manual lalu dikirim langsung ke server |
Ketiga baris tabel memuat pola yang sama, yaitu pengaman yang dipasang pada wilayah yang berada di luar kendali server. Validasi, penyembunyian, dan pembatasan halaman semuanya berhenti berlaku begitu permintaan disusun dengan alat lain. Kebiasaan yang perlu dilatih adalah menanyakan permintaan apa saja yang dapat dibangun terhadap server, bukan hanya apa yang dilakukan halamannya.
Kasus penyalahgunaan#
Kasus penyalahgunaan (abuse case) adalah penurunan kasus penggunaan (use case) dari sudut pandang orang yang ingin merugikan sistem. Kasus penggunaan menyatakan alur yang diharapkan, misalnya pemohon memesan alat tulis dengan jumlah tertentu. Kasus penyalahgunaan membalik alurnya dengan menguji setiap masukan terhadap nilai negatif, tipe yang tidak diduga, dan jumlah yang melampaui batas wajar.
Berkas berikut memuat penghitung total pesanan dalam dua versi, yaitu versi tanpa validasi dan versi yang memeriksa tipe serta rentang nilainya. Empat kasus dijalankan berurutan agar perbedaannya terlihat.
"""Demo kasus penyalahgunaan: total pesanan tanpa validasi
dibandingkan dengan versi yang memvalidasi masukannya."""
def total_pesanan(jumlah, harga_satuan):
# versi tanpa validasi: menerima apa pun yang diberikan pemanggil
return jumlah * harga_satuan
def total_pesanan_aman(jumlah, harga_satuan):
# versi dengan validasi: tipe dan rentang nilai diperiksa lebih dahulu
if not isinstance(jumlah, int) or isinstance(jumlah, bool):
return None
if not isinstance(harga_satuan, (int, float)) or isinstance(harga_satuan, bool):
return None
if jumlah < 1 or jumlah > 100:
return None
if harga_satuan < 0 or harga_satuan > 1000000:
return None
return jumlah * harga_satuan
kasus = [
("pesanan wajar", 3, 2500),
("jumlah negatif", -5, 2500),
("jumlah berupa bool", True, 2500),
("harga berupa string", 3, "2500"),
]
for nama, jumlah, harga in kasus:
print(nama)
print(" tanpa validasi :", total_pesanan(jumlah, harga))
print(" dengan validasi:", total_pesanan_aman(jumlah, harga))pesanan wajar
tanpa validasi : 7500
dengan validasi: 7500
jumlah negatif
tanpa validasi : -12500
dengan validasi: None
jumlah berupa bool
tanpa validasi : 2500
dengan validasi: None
harga berupa string
tanpa validasi : 250025002500
dengan validasi: NoneTiga kasus terakhir memperlihatkan penyalahgunaan yang berbeda satu sama lain. Jumlah negatif menghasilkan total -12500, yang pada aplikasi nyata berarti saldo pemohon bertambah sebesar nilai itu setiap pesanan dikirim. Nilai True diperlakukan Python sebagai bilangan 1, sehingga lolos sebagai jumlah yang sah pada versi tanpa validasi. Harga berupa string memicu pengulangan string, sehingga total menjadi 250025002500 dan seluruh laporan yang bergantung padanya ikut kacau. Versi yang memvalidasi mengembalikan None untuk ketiganya, sehingga pemanggil dapat menolak pesanan sebelum pesanan menyentuh basis data.
Cacat semacam ini tidak tertangani oleh framework maupun konfigurasi server karena akarnya ada pada rancangan aturan bisnis. Kategori A06 Insecure Design pada OWASP Top 10:2025 menaungi kegagalan rancangan seperti ini, sedangkan A01 Broken Access Control menaungi kegagalan pemeriksaan izin yang menyertainya. Kasus penyalahgunaan yang disusun lebih dahulu memaksa kedua pemeriksaan itu masuk ke dalam kode sejak awal, sebelum fitur dirilis.
Kesalahan umum#
Kesalahan pada tahap ini jarang berupa kesalahan teknis dan lebih sering berupa kebiasaan menelaah yang belum terbentuk. Kebiasaan semacam ini sulit terdeteksi karena kode yang dihasilkan justru berjalan normal pada alur wajar. Tiga kebiasaan berikut muncul paling sering pada pemula.
- Memercayai masukan karena berasal dari aplikasi sendiri. Perbaikannya adalah memindahkan seluruh keputusan penting ke sisi server, setelah data menyeberangi batas kepercayaan.
- Menguji hanya alur normal. Perbaikannya adalah menurunkan minimal satu kasus penyalahgunaan dari setiap kasus penggunaan, lalu menjalankannya sebagai kasus uji bersama kasus yang wajar.
- Menghafal daftar kerentanan tanpa berlatih menelaah. Daftar seperti OWASP Top 10 berguna sebagai peta, tetapi temuan baru hanya muncul apabila fitur ditelaah dengan pola pikir penyerang.
Ketiga kebiasaan tersebut teratasi dengan latihan yang sama, yaitu menandai setiap batas kepercayaan pada sebuah fitur, menuliskan asumsi di setiap batasnya, lalu membalik setiap asumsi menjadi kasus penyalahgunaan. Latihan semacam ini cepat dilakukan dan tidak memerlukan alat tambahan. Hasilnya berupa daftar pemeriksaan yang menyertai kode sejak hari pertama.
Ringkasan#
- Batas kepercayaan (trust boundary) memisahkan wilayah dengan tingkat kepercayaan berbeda, dan data yang menyeberanginya selalu diperlakukan sebagai masukan yang tidak dipercaya.
- Asumsi tersembunyi adalah keyakinan yang tidak pernah diperiksa oleh kode dan biasanya menyandarkan pengaman pada wilayah klien.
- Kasus penyalahgunaan diturunkan dari kasus penggunaan dengan menguji nilai negatif, tipe tak terduga, dan rentang yang melampaui batas, lalu ditangani dengan validasi di sisi server.
Referensi#
- OWASP Top 10 — OWASP Foundation — Daftar risiko keamanan aplikasi web yang paling kritis dan menjadi acuan jalur ini.
- OWASP Top 10:2025 — OWASP Foundation — Rilis 2025 yang menempatkan Broken Access Control dan Insecure Design di antara risiko utamanya.