Apa Itu SQL Injection dan Bagaimana Cara Mencegahnya?
Penjelasan praktis tentang serangan SQL injection, contoh nyata, dan solusi konkret yang benar-benar menghentikannya dalam kode produksi.
SQL injection sudah ada sejak akhir 1990-an dan masih menjadi salah satu cara paling umum aplikasi web dikompromikan. Bug-nya sederhana: penyerang mengirimkan input yang diinterpretasikan sebagai kode SQL daripada data biasa, dan database melakukan sesuatu yang tidak pernah seharusnya terjadi.
Cara serangan bekerja sebenarnya
Bayangkan form login yang membangun query seperti ini di PHP:
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
Jika aplikasi tidak membersihkan input, penyerang mengetik admin' -- ke dalam field username. Query menjadi:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
-- mengomentari sisa baris, sehingga pengecekan password tidak pernah terjadi. Itu adalah auth bypass klasik. Penyerang juga menggunakan UNION SELECT untuk menarik data dari tabel lain, atau menumpuk query dengan titik koma untuk menjalankan sesuatu yang merusak seperti DROP TABLE users; jika driver memungkinkan beberapa statement.
Ada juga blind SQL injection, di mana aplikasi tidak menampilkan hasil query secara langsung. Penyerang menyimpulkan informasi melalui timing (SLEEP(5) di MySQL) atau respons boolean (apakah halaman berperilaku berbeda untuk kondisi true vs. false). Tools seperti sqlmap mengotomatisasi jenis ekstraksi ini setelah parameter yang rentan ditemukan.
Mengapa concatenation string adalah akar masalahnya
Setiap varian serangan ini kembali ke satu hal: mencampur kode dan data dalam string yang sama. Database tidak bisa membedakan antara nilai yang sah dan syntax yang disuntikkan karena mereka tiba di channel yang sama. Escaping quote membantu dalam beberapa kasus tetapi itu rapuh — encoding berbeda, second-order injection (data disimpan sekali, kemudian digunakan ulang secara tidak aman nanti), dan quirk spesifik driver semuanya menciptakan jalur bypass. Escaping adalah patch, bukan perbaikan.
Parameterized queries adalah perbaikan sebenarnya
Perbaikannya adalah memisahkan kode SQL dari data pengguna di level driver, menggunakan parameterized queries (juga disebut prepared statements). Database menerima struktur query terlebih dahulu, kemudian mengikat nilai setelahnya, sehingga input pengguna tidak pernah bisa mengubah makna query.
Di Python dengan psycopg2:
cur.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
Di Node.js dengan mysql2:
connection.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);
Di Java dengan JDBC:
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?");
stmt.setString(1, username);
stmt.setString(2, password);
Perhatikan polanya: placeholder (%s, ?) memegang tempat untuk data, dan nilai aktual dilewatkan secara terpisah. Tidak ada string concatenation, tidak ada escaping manual yang dibutuhkan. Ini bekerja untuk sebagian besar query yang akan Anda tulis dalam aplikasi normal.
Bagaimana dengan nama tabel atau kolom yang dinamis?
Parameterisasi menangani nilai tetapi bukan identifier — Anda tidak bisa mengikat nama tabel sebagai parameter. Jika aplikasi Anda perlu memilih tabel secara dinamis (jarang, dan sering kali tanda design yang buruk), whitelist nilai yang diizinkan terhadap list yang dikodekan keras daripada mempercayai input pengguna secara langsung:
allowed_tables = {'orders', 'invoices', 'customers'}
if table_name not in allowed_tables:
raise ValueError("Invalid table")
Jangan pernah membangun nama identifier melalui string formatting dari input pengguna, bahkan dengan escaping.
Pertahanan berlapis di luar query itu sendiri
Parameterized queries adalah kontrol utama, tetapi beberapa hal lain penting:
- Least privilege pada akun database. User DB aplikasi tidak seharusnya memiliki
DROP,ALTER, atau akses ke schema yang tidak terkait. Jika injection terlewatkan, privilege terbatas membatasi kerusakan. - ORMs membantu secara default. Django ORM, SQLAlchemy, dan Hibernate semuanya parameterisasi query secara otomatis saat Anda menggunakan metode query-building standar mereka. Risiko muncul kembali saat developer jatuh ke raw SQL atau menggunakan
.extra()/text()calls dengan string interpolation — jadi audit spot tersebut secara khusus. - Input validation adalah layer sekunder, bukan pengganti. Memeriksa bahwa field email terlihat seperti email adalah praktik baik, tetapi itu tidak menghentikan injection sendiri — penyerang menemukan payload kreatif yang masih melewati validasi longgar.
- WAF bisa menangkap pola serangan yang dikenal, tetapi itu adalah layer deteksi, bukan perbaikan untuk kode yang mendasar.
Menguji kode Anda sendiri untuk bug ini
Jalankan query Anda melalui static analysis tool (Bandit untuk Python, Semgrep dengan SQL injection rulesets) sebagai bagian dari CI. Untuk testing manual, coba suntikkan satu quote (') ke setiap input field dan lihat pesan error SQL yang bocor dalam respons — itu sering kali tanda pertama bahwa query tidak parameterisasi.
Jika Anda ingin menggali lebih dalam, Web Security track Korra Studio mencakup injection bersama XSS dan auth bypass, dan segment Databases menjelaskan query design patterns yang menghindari kelas bug ini sepenuhnya.
Ditulis dengan bantuan AI, ditinjau dan dipublikasikan oleh Michal Pilch (CISSP), Korra Studio.
Ini satu catatan dari basis pengetahuan Korra Studio — platform ini memasangkan setiap topik dengan bimbingan privat.
Mulai gratisarrow_forward