Review Pencegahan SQL Injection untuk Tim Aplikasi
SQL injection muncul saat data mengubah struktur query. Parameter binding memisahkan nilai dari sintaks; escaping lebih lemah dan spesifik database.
Temukan seam query dinamis
Review filter pencarian, field sort, report builder, konsol admin, dan raw-query escape ORM. Contoh: bind nama pelanggan sebagai parameter. Contoh lain: pilih kolom ORDER BY dari enum tetap di server karena identifier umumnya tidak dapat diparameterkan.
Checklist konstruksi query
| Area | Pola aman | Uji |
|---|---|---|
| nilai | prepared statement | quote tetap menjadi data |
| identifier | allowlist server | sort tidak dikenal ditolak |
| privilege | akun DB sempit | jalur baca tidak dapat drop table |
| error | respons generik | detail SQL tidak muncul |
Panduan pencegahan SQL injection OWASP dan CWE-89 menjadi rujukan utama.
Aturan keputusan: nilai yang berasal dari request tidak boleh mengubah tata bahasa SQL.
Perbaikan
Ganti konkatenasi dengan binding, allowlist pilihan struktural yang tidak terhindarkan, kecilkan privilege database, dan uji jalur error. Penggunaan ORM bukan bukti aman: raw fragment dan interpolasi tidak aman tetap harus direview. Audit kode dapat menemukan seam tersebut.
Jadikan tata bahasa milik server
Template query harus menentukan struktur SQL sebelum nilai request datang. Bind nilai melalui parameter driver dan buat konversi tipe eksplisit. Bila arah sort, kolom, atau pilihan tabel tidak dapat di-bind, petakan enum request kecil ke string server tetap; tolak nilai lain. Telusuri API raw query, interpolasi, helper migrasi, report, dan stored procedure untuk SQL dinamis.
Validasi dengan request nyata dan akun database, bukan code review saja. Payload quote harus tetap menjadi nilai literal, pilihan sort tidak dikenal harus gagal, dan akun privilege rendah tidak boleh dapat menjalankan tindakan lain. Simpan lokasi query, template, parameter, grant role, respons, dan test regresi. Owner: pemilik layanan data. Lulus: data request tidak pernah mengubah tata bahasa query dan error tidak mengungkap detail SQL. Gagal: struktur query berubah, tindakan berprivilege berhasil, atau error database bocor. Pengecualian menyatakan scope, kontrol akses kompensasi, persetujuan risiko, owner perbaikan, dan kedaluwarsa.
Contoh review query
Nilai aman memakai template query dengan driver binding; nilai itu tidak pernah mengonkatenasi teks request. Pemilihan sort aman memetakan enum request kecil ke identifier server tetap dan arah tetap. Helper escaping generik bukan jalur persetujuan. Review juga migrasi dan maintenance job karena query dengan paparan lebih rendah dapat berjalan memakai credential tinggi.
Bukti konstruksi query
Output yang diharapkan: lokasi query, ID template, tipe parameter terikat, pilihan enum struktural, role database, respons error, kasus regresi. Bukti ini menghubungkan template query dengan hasil role yang tercatat.
Kegagalan teruji: Parameter sort report meminta kolom di luar peta server. Endpoint harus menolaknya, bukan mengonkatenasi identifier dari input.
Kasus tepi: Nilai prepared tidak mengamankan SQL prosedur dinamis. Audit body procedure dan skrip maintenance untuk eksekusi statement yang dirakit.
Uji penutupan: Jalankan payload quote memakai role setara produksi pada database uji. Penutupan lulus bila data kembali mengikuti semantik nilai literal dan privilege tetap sempit.
Batas struktur dinamis
Daftarkan setiap bagian query yang bukan nilai terikat: ordering, arah pagination, field report terpilih, partisi tabel, schema tenant, dan nama procedure. Untuk tiap bagian, gunakan peta server terbatas atau desain ulang bentuk request. Catat structural key yang ditolak dengan kategori aman, bukan seluruh query. Parameter binding juga memerlukan tipe benar: memperlakukan limit numerik sebagai teks dapat tetap tahan injection namun menciptakan penyalahgunaan resource.
Uji jalur kode yang berjalan di luar penanganan HTTP normal, termasuk ekspor latar belakang, rekonsiliasi terjadwal, maintenance CLI, dan skrip migrasi. Jalur tersebut sering memakai role database kuat dan menerima data dari file atau queue, bukan form. Kasus regresi berguna menegaskan hasil query serta izin database: data pengguna valid mengembalikan baris yang diharapkan; nilai struktural percobaan gagal; write terlarang tidak dapat berhasil pada role baca.
Capture penggunaan API prepared statement pada runtime test atau driver log tanpa mengekspos nilai pengguna. Kegagalan penutupan terjadi bila jalur reporting baru menginterpolasi identifier walau query aplikasi utama sudah terikat. Review query builder setelah upgrade.
Penanganan error database memerlukan bukti terpisah dari konstruksi query. Picu kegagalan constraint atau koneksi terkontrol lalu pastikan respons aplikasi tidak membocorkan teks SQL, nama schema, credential, atau detail stack. Simpan diagnostik penuh hanya pada log server terbatas dengan korelasi request. Query timeout dan row limit juga mengurangi dampak input mahal tetapi valid secara sintaks. Uji pencarian luas yang diizinkan dan verifikasi perilaku limit sesuai ekspektasi produk tanpa beralih ke SQL dinamis tidak aman.
Pemeriksaan akhir menghubungkan setiap jalur query dengan bukti parameter binding dan hasil uji input bermusuhan. Output diharapkan: nilai pengguna tidak mengubah struktur SQL atau mengungkap diagnostik database. Kasus tepi: filter urutan atau kolom memakai identifier dinamis; batasi pada allowlist. Tutup hanya setelah query terdeploy dan log terbatas menunjukkan perilaku sesuai kebijakan.