Beranda Blog Store
Cyber Security

Audit Keamanan Aplikasi Web Sendiri: Mencari IDOR, CSRF, dan Kebocoran Berkas dengan Alat Gratis

23 Agu 2026 Hartono 5 menit baca 8 Dilihat

Kalau Anda mengembangkan aplikasi web dan belum pernah mencoba membobolnya sendiri, Rekan ArtonLabs, tulisan ini adalah ajakan untuk melakukannya dengan aman.

Audit keamanan tidak harus menunggu anggaran untuk pentester. Sebagian besar celah yang kami temukan di aplikasi web, termasuk di aplikasi kami sendiri, termasuk tiga kelas yang bisa dicari dengan alat gratis dan kesabaran: akses ke data orang lain hanya dengan mengganti id (IDOR), permintaan yang bisa dipalsukan lintas situs (CSRF), dan berkas yang seharusnya privat tetapi tersaji ke publik. Tulisan ini adalah daftar periksa yang kami jalankan pada aplikasi sebelum diserahkan ke klien, beserta contoh temuan sungguhan.

Daftar Isi

Aturan Main: Hanya Aplikasi Sendiri

Semua teknik di bawah hanya boleh dijalankan pada aplikasi milik Anda atau yang pemiliknya memberi izin tertulis. Lakukan di salinan uji, bukan di produksi, dengan akun uji, dan catat semua yang Anda coba. Uji di produksi dengan akun sungguhan pernah meninggalkan data uji di akun pengguna sungguhan pada salah satu proyek kami; sejak itu, selalu salinan.

IDOR: Ganti Id, Lihat Apa yang Terjadi

Buat dua akun uji, A dan B. Sebagai A, buat data apa pun: pesanan, laporan, unggahan. Catat id-nya dari URL atau respons API. Lalu sebagai B, akses URL yang sama dengan id milik A, termasuk endpoint API yang dipanggil halaman, bukan hanya halamannya:

# login sebagai B, simpan cookie
curl -c b.txt -b b.txt -d 'username=b&password=...' https://uji.contoh.com/masuk/
# coba akses data milik A
curl -b b.txt -i https://uji.contoh.com/api/laporan/17

Jawaban yang benar adalah 403 atau 404, bukan 200 dengan data A. Kami pernah menemukan endpoint status pekerjaan yang tidak memeriksa pemilik sama sekali, bahkan tanpa login, sehingga siapa pun bisa memantau progres analisis orang lain dengan menebak angka. Periksa juga metode lain: GET mungkin aman tetapi DELETE tidak. Di Django, polanya sederhana: setiap query menyertakan owner=request.user, dan uji otomatis memastikan akun lain mendapat 404.

CSRF: Apakah Endpoint POST Dilindungi?

Untuk setiap endpoint yang mengubah data lewat sesi cookie, kirim POST tanpa token CSRF:

curl -b a.txt -i -X POST https://uji.contoh.com/api/laporan/17/hapus/

Harus ditolak dengan 403. Kalau diterima, situs lain bisa membuat browser pengguna mengirim permintaan itu tanpa sepengetahuannya. Kerangka kerja modern melindungi form HTML secara bawaan, tetapi API yang dibuat dengan pustaka terpisah sering terlewat. Pada django-ninja, misalnya, perlindungan CSRF baru aktif saat endpoint memakai autentikasi sesi secara eksplisit; kami pernah menemukan empat endpoint POST terbuka karena ini. Endpoint yang memakai token Bearer tidak rentan CSRF, karena tidak bergantung pada cookie.

Kebocoran Berkas dan Informasi

for p in .env .git/HEAD .git/config backup.zip db.sqlite3 static/style.css.bak \
         .DS_Store composer.json package.json phpinfo.php; do
  printf "%-28s %s\n" "$p" "$(curl -s -o /dev/null -w '%{http_code}' https://uji.contoh.com/$p)"
done

Semua harus 404 atau 403. Tiga temuan nyata dari aplikasi kami sendiri: berkas .bak di folder statis yang ikut tersaji setelah collectstatic; halaman dokumentasi API yang menerbitkan daftar lengkap endpoint kepada siapa pun; dan halaman galat dengan DEBUG menyala yang menampilkan variabel lingkungan. Periksa juga respons galat 500 dan 404 di produksi: jejak tumpukan dan versi perangkat lunak tidak boleh terlihat. Dan jalankan gitleaks atau trufflehog pada repositori untuk menemukan rahasia yang pernah ter-commit; rahasia yang sudah masuk riwayat Git harus diganti, bukan hanya dihapus.

Unggahan Berkas dan Path Traversal

Kalau aplikasi menerima unggahan, coba mengunggah berkas bernama ../../../tmp/uji.txt, berkas .php atau .html dengan tipe yang dipalsukan, dan arsip zip yang berisi anggota dengan jalur ../ kalau aplikasi mengekstrak arsip. Lalu periksa di mana berkas itu mendarat dan apakah ia bisa diakses atau dieksekusi lewat URL. Nama berkas harus dibuat server, jenis isi diperiksa dari isinya, dan folder unggahan tidak boleh menjalankan skrip. Zip-slip, yaitu arsip yang menulis ke luar folder tujuan, adalah salah satu skenario yang diuji pengembang VinzaPanel pada file manager mereka sendiri, dan layak Anda uji pada aplikasi Anda.

Halaman Masuk

Coba seratus kali login gagal dengan skrip sederhana. Kalau percobaan ke-seratus masih dijawab sama cepatnya dengan yang pertama, tidak ada pembatas, dan sandi pengguna bisa ditebak dengan sabar. Pembatas per akun dan per alamat dengan jawaban 429, ditambah 2FA untuk admin, menutupnya.

curl -s -I https://uji.contoh.com/ | grep -iE 'strict-transport|x-frame|x-content-type|content-security|set-cookie'

Yang dicari: HSTS aktif, X-Frame-Options atau CSP frame-ancestors untuk mencegah clickjacking, X-Content-Type-Options: nosniff, dan cookie sesi dengan Secure, HttpOnly, dan SameSite. Hati-hati header ganda: kalau Nginx dan aplikasi sama-sama mengirim X-Frame-Options dengan nilai berbeda, perilakunya tidak terdefinisi; pilih satu sumber. Django punya manage.py check --deploy yang mencetak sebagian besar ini.

Alat Gratis yang Membantu

OWASP ZAP memindai otomatis dan menyediakan proxy untuk melihat serta mengubah permintaan; mode "spider" lalu "active scan" pada salinan uji menemukan banyak hal dasar. Nikto memeriksa konfigurasi server dan berkas umum yang bocor. Untuk dependensi, pip-audit dan npm audit mencocokkan versi terkunci dengan basis data kerentanan. Pembaca log akses Anda sendiri adalah alat yang paling diremehkan: pola permintaan 404 ke jalur yang tidak pernah ada menunjukkan apa yang dicari penyerang, dan kadang menunjukkan apa yang mereka temukan.

Mengubah Temuan Menjadi Uji Otomatis

class KeamananTest(TestCase):
    def test_laporan_orang_lain_404(self):
        self.client.force_login(self.b)
        r = self.client.get(f"/api/laporan/{self.laporan_a.id}")
        self.assertEqual(r.status_code, 404)

    def test_post_tanpa_csrf_ditolak(self):
        c = Client(enforce_csrf_checks=True)
        c.force_login(self.a)
        r = c.post(f"/api/laporan/{self.laporan_a.id}/hapus/")
        self.assertEqual(r.status_code, 403)

    def test_berkas_cadangan_tidak_tersaji(self):
        self.assertEqual(self.client.get("/static/style.css.bak").status_code, 404)

Setiap temuan menjadi satu uji, sehingga celah yang sudah ditutup tidak bisa terbuka lagi diam-diam saat kode berubah. Uji seperti ini murah dan merupakan bagian audit yang paling bertahan lama.

Penutup

Dua akun uji, curl, dan satu sore yang teliti menemukan sebagian besar celah yang sebenarnya dieksploitasi orang. Audit profesional tetap berharga untuk aplikasi yang sensitif, tetapi datang ke sana dengan tiga kelas celah ini sudah tertutup membuat audit itu jauh lebih bermanfaat, dan jauh lebih tidak memalukan.

Semoga audit pertama Anda menemukan sesuatu yang kecil dan mudah diperbaiki. Kalau yang ditemukan lebih besar, jangan ragu menghubungi kami lewat halaman kontak.