Kasus situs yang datanya bocor atau berubah tanpa izin sering berawal dari SQL injection, teknik menyisipkan perintah SQL berbahaya melalui input pengguna. Di PHP, celah ini muncul ketika kode menggabungkan langsung variabel ke dalam query. Prepared statement memisahkan kode SQL dari data, sehingga perintah berbahaya tidak ikut dieksekusi. Artikel ini membahas cara mencegah SQL injection di PHP lewat prepared statement dan kebiasaan lain yang menutup celahnya.
Apa Itu SQL Injection dan Kenapa Berbahaya?
SQL injection terjadi ketika aplikasi menerima input pengguna lalu memasukkannya ke dalam query SQL tanpa pengamanan yang tepat. Penyerang bisa mengirim teks seperti ' OR '1'='1 pada kolom login. Jika kode Anda rentan, query berubah menjadi kondisi yang selalu bernilai benar. Penyerang bisa masuk tanpa kredensial valid, mencuri data, atau menghapus tabel.
Kerugiannya mencakup integritas sistem yang rusak. Perusahaan kehilangan kepercayaan pengguna, dan pemilik aplikasi menanggung biaya pemulihan yang tidak sedikit.
Mengapa Prepared Statement Efektif Mencegah SQL Injection
Prepared statement memisahkan query SQL dari nilai yang dimasukkan. Anda mendefinisikan struktur query lebih dulu dengan placeholder, lalu mengikat nilai ke placeholder tersebut. Database memperlakukan nilai sebagai data murni, bukan bagian dari perintah SQL. Karakter khusus yang dikirim pengguna tidak akan mengubah logika query.
Ada dua jenis placeholder yang umum: posisi (?) dan nama (:nama). Keduanya aman selama Anda memakai parameter binding dan tidak menyisipkan variabel langsung ke string query.
Contoh Kode Rentan vs Aman dengan Prepared Statement
Perhatikan potongan kode berikut yang rentan terhadap SQL injection:
$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $query);
Jika penyerang mengisi username dengan admin' --, query menjadi SELECT * FROM users WHERE username = 'admin' --' AND password = ''. Tanda -- membuat sisa query diabaikan, sehingga penyerang bisa masuk sebagai admin tanpa password.
Versi aman menggunakan prepared statement dengan mysqli:
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();
Input pengguna tidak pernah bercampur dengan struktur query. Database memperlakukan admin' -- sebagai string biasa, bukan perintah.
Langkah-Langkah Menerapkan Prepared Statement di PHP
Alur umum yang bisa Anda ikuti:
- Siapkan koneksi database menggunakan mysqli atau PDO.
- Buat query dengan placeholder (
?atau:nama). - Panggil
prepare()untuk menyiapkan statement. - Ikat parameter menggunakan
bind_param()(mysqli) ataubindValue()(PDO). - Jalankan statement dengan
execute(). - Ambil hasil jika diperlukan.
Periksa tipe data pada bind_param. Untuk string gunakan “s”, integer “i”, double “d”, dan blob “b”. Tipe yang benar membantu database menginterpretasikan nilai.
Kesalahan Umum yang Membuat Prepared Statement Tidak Efektif
Meskipun sudah menggunakan prepared statement, beberapa jebakan bisa membuat kode tetap rentan. Salah satunya menyisipkan variabel langsung ke dalam query saat memanggil prepare(), misalnya:
$stmt = $conn->prepare("SELECT * FROM users WHERE id = $id");
Ini sama saja dengan query biasa. Selalu gunakan placeholder. Kesalahan lain adalah tidak memvalidasi tipe data saat binding, atau memakai mysqli_real_escape_string sebagai pengganti prepared statement. Fungsi escape membantu, tetapi tidak sekuat prepared statement dan bisa gagal pada kondisi tertentu.
Perhatikan juga penggunaan dynamic query seperti ORDER BY ?. Prepared statement tidak bisa mengikat nama kolom atau tabel. Untuk kasus seperti ini, gunakan whitelist nilai yang diizinkan.
Praktik Terbaik Keamanan Database di PHP
Selain prepared statement, beberapa kebiasaan meningkatkan keamanan:
- Batasi hak akses user database sesuai kebutuhan aplikasi.
- Jangan tampilkan pesan error database ke pengguna; log saja untuk pengembang.
- Selalu validasi dan sanitasi input di sisi server, meskipun sudah menggunakan prepared statement.
- Perbarui PHP dan library database secara berkala.
- Gunakan HTTPS untuk melindungi data saat transit.
Untuk proyek yang lebih besar, struktur kode yang rapi memudahkan audit keamanan. Anda bisa membaca panduan Cara Menulis Kode PHP, JS, dan CSS Tetap Rapi Saat Proyek Bertambah agar kode tetap terorganisir.
Ringkasan
SQL injection bisa dihindari dengan prepared statement. Dengan memisahkan query dan data, Anda mencegah penyerang mengubah logika SQL. Terapkan langkah-langkah di atas secara konsisten, dan kombinasikan dengan praktik keamanan lain seperti validasi input dan pembatasan hak akses database.
Pertanyaan yang Sering Diajukan
Apakah prepared statement cukup untuk mencegah semua SQL injection?
Prepared statement sangat efektif mencegah injeksi melalui nilai yang diikat. Jika Anda membangun query dinamis dengan menggabungkan nama kolom atau operator secara langsung, risiko masih ada. Gunakan whitelist untuk bagian query yang tidak bisa di-parameterized.
Apakah saya perlu menggunakan prepared statement jika sudah memakai mysqli_real_escape_string?
mysqli_real_escape_string berguna untuk escaping karakter khusus, tetapi tidak sekuat prepared statement. Prepared statement lebih aman karena memisahkan peran kode dan data di level database. Gunakan prepared statement sebagai metode utama.
Bisakah prepared statement digunakan untuk query INSERT, UPDATE, dan DELETE?
Ya, prepared statement berlaku untuk semua jenis query yang menggunakan parameter, termasuk INSERT, UPDATE, dan DELETE. Anda hanya perlu menyesuaikan placeholder dan binding parameter sesuai jumlah dan tipe data.