Membedah SQL Injection (SQLi)
12 Jun 2026 | Oleh: rastono sumardi
SQL Injection terjadi ketika aplikasi web salah mengartikan input dari pengguna sebagai sebuah instruksi (perintah SQL) dan bukan sekadar data. Hal ini biasanya berawal dari praktik buruk merangkai string (string concatenation) untuk membangun kueri secara dinamis.
Contoh Kasus Klasik (Kueri yang Rentan): Bayangkan sebuah skrip login sederhana yang langsung menggabungkan input pengguna ke dalam perintah SQL:
$username = $_POST['username']; // Input langsung dari form
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '...'";
Jika seorang peretas memasukkan admin' -- pada kolom username, kueri yang diterima dan dieksekusi oleh server MySQL akan menjadi:
SELECT * FROM users WHERE username = 'admin' --' AND password = '...'
Tanda -- di MySQL berfungsi sebagai penanda awal komentar. Akibatnya, logika pengecekan password di belakangnya diabaikan sepenuhnya oleh sistem, dan peretas berhasil mengelabui database untuk masuk sebagai admin.
Bagaimana Prepared Statements Menyelesaikan Masalah?
Prepared statements mengubah cara aplikasi berkomunikasi dengan database. Alih-alih "mengirim satu kalimat utuh" yang bisa disisipi perintah tersembunyi, sistem akan "mengirim kerangka instruksi terlebih dahulu, lalu mengisi bagian rumpangnya belakangan."
Proses ini memisahkan logika dan data melalui dua tahap utama:
-
Prepare (Persiapan Logika): Aplikasi mengirimkan struktur dasar kueri (templat) ke server database. Placeholder (biasanya tanda
?atau parameter bernama seperti:username) digunakan untuk menandai posisi data. Server database kemudian melakukan parsing, kompilasi, dan optimasi kueri pada tahap ini dan mengunci strukturnya. -
Execute (Pengiriman Data): Aplikasi mengirimkan nilai data (input pengguna) secara terpisah ke database.
Kunci Keamanannya: Karena struktur kueri sudah dikunci (pre-compiled) pada tahap Prepare, database sudah tahu persis mana yang merupakan perintah SQL (seperti SELECT, WHERE) dan mana yang merupakan data murni. Meskipun input pengguna mengandung karakter berbahaya seperti ' OR '1'='1, database hanya akan menganggapnya sebagai teks biasa. Sistem akan mencari pengguna yang namanya persis "' OR '1'='1", bukan mengeksekusinya sebagai perintah logika bypass.
Penerapan Standar dalam PHP (Native PDO)
Berikut adalah anatomi penulisan standar menggunakan PDO saat berinteraksi dengan MySQL agar kebal dari SQL Injection:
// 1. Konfigurasi Koneksi PDO yang Aman
$dsn = "mysql:host=localhost;dbname=nama_database;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
// Penting: Matikan emulasi agar proses 'prepare' benar-benar
// ditangani oleh engine database MySQL, bukan sekadar difilter oleh PHP
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, 'user_db', 'password_db', $options);
// 2. Tahap PREPARE (Menyiapkan kerangka logika menggunakan parameter bernama)
$username_input = $_POST['username'];
$sql = "SELECT id, username, role FROM users WHERE username = :username LIMIT 1";
$stmt = $pdo->prepare($sql);
// 3. Tahap EXECUTE (Mengirimkan data murni)
$stmt->execute(['username' => $username_input]);
$user = $stmt->fetch();
Penerapan pada Framework (Contoh: CodeIgniter 4)
Dalam pengembangan portal publik atau sistem informasi berbasis framework modern dengan arsitektur MVC seperti CodeIgniter 4, perlindungan PDO ini biasanya sudah diabstraksi dan diotomatisasi.
Penggunaan Query Builder (Otomatis Aman): Ketika Anda menggunakan metode Query Builder, sistem framework secara otomatis melakukan escaping dan binding di belakang layar.
$builder = $db->table('users');
$user = $builder->where('username', $username_input)->get()->getRowArray();
Penggunaan Raw Query (Wajib Binding Parameter): Jika Anda dihadapkan pada situasi di mana Anda harus merakit kueri kompleks secara manual (raw query), standarnya adalah selalu menggunakan fitur bindings (tanda ?) seperti layaknya PDO murni.
$sql = "SELECT * FROM users WHERE username = ? AND status = ?";
// Data dikirim sebagai array pada parameter kedua, terpisah dari logika SQL
$db->query($sql, [$username_input, 'active']);
Dengan memastikan setiap interaksi ke database melewati mekanisme pemisahan data dan logika ini, Anda menutup celah kerentanan yang paling sering dieksploitasi oleh peretas.