Mengenal Prepared Statement

Tulisan ini terinspirasi dari pertanyaan salah satu rekan tim.

Sebenarnya, cara kerja Prepared Statement itu bagaimana sih? Kok bisa untuk menangkal SQL Injection

SQL Injection and Prepared Statement

SQL Injection merupakan satu dari sekian kerentanan yang umum ditemukan di web application. Untuk memitigasi kerentanan ini, kami memberikan beberapa rekomendasi dan saran antara lain dengan melakukan sanitasi (filter) dan menggunakan Prepared Statement ketika mengeksekusi query.

Bagaimana bisa Prepared Statement melindungi dari SQL Injection?

Ide dasar dari Prepared Statement (atau Parameterized Statement) sebenarnya cukup sederhana: memisahkan antara query dan data (parameter).

SQL Injection terjadi karena adanya percampuran antara “kode” dan data. Kode adalah query yang ditetapkan oleh developer dan data berasal dari input pengguna. Akibat kurangnya sanitasi, input yang seharusnya hanya berperan sebagai data akhirnya mempengaruhi dan mengubah query.

Misalnya saja, developer menciptakan query sebagai berikut:

SELECT a, b, c FROM tabelku WHERE id=’$id’;

Ini bukanlah query akhir yang akan dikirimkan ke DBMS (DataBase Management System). Aplikasi terlebih dahulu mengisikan nilai $id yang sesuai. Misal $id bernilai 1, maka query tersebut akan menjadi

SELECT a, b, c, FROM tabelku WHERE id=’1'

Bagaimana jika $id dapat diisikan nilai lain? Bagaimana jika attacker dapat mengisikan sembarang nilai ke $id? Jika demikian attacker bisa mengubah query akhir menjadi sesuai yang diinginkan. Misal, id berisi 1' OR ‘1’=’1, maka query akan menjadi.

SELECT a, b, c FROM tabelku WHERE id=’1' OR ‘1’=’1'

Query akhir yang telah disubstitusi inilah yang akan dikirimkan ke dan dieksekusi oleh DBMS.

Pada pendekatan Prepared Statement, eksekusi query dipecah menjadi dua tahap, yaitu Prepare dan Execute.

Pada tahap pertama, developer menetapkan sebuah template query. Template tidak akan menyebutkan data apa yang digunakan. Semua kemunculan data akan disimbolkan dengan sesuatu (placeholder).

SELECT a, b, c, FROM tabelku WHERE id = ?

DBMS kemudian akan melakukan kompilasi (parse, optimize, translate) dan membentuk yang namanya AST (Abstract Syntax Tree) untuk query tersebut, tanpa melakukan eksekusi query.

Tahap kedua adalah memberikan parameter query. Pada tahap ini kita akan menetapkan nilai yang tepat untuk mengisi “?” di query (disebut pula dengan binding). Di tahap inilah DBMS akan mengeksekusi (template) query menggunakan data yang sesuai.

Sekilas nampak mirip. Namun pada Prepared Statement, eksekusi dilakukan terhadap query yang telah dibentuk. Data tidak akan mengubah statement query. Jika data berisi hal-hal yang menyebabkan perubahan sintaks atau pelanggaran (violation), maka DBMS akan menolak.

Upacara Prepared Statement

Framework atau platform pengembangan populer umumnya mendukung Prepared Statement dengan cara masing-masing. Karena itu kami biasanya menyarankan untuk merujuk pada dokumentasi masing-masing framework untuk melakukan Prepared Statement.

Umumnya masing-masing driver akan menyediakan fungsi untuk:

  • Membentuk prepared statement
  • Binding parameter, set parameter sebagai tipe tertentu (string / integer)
  • Execute statement.

Penggunaan Prepared Statement untuk setiap driver mengikuti tata cara atau urutan tertentu. Dimulai dari pembentukan prepared statement, binding terhadap semua parameter, hingga diakhiri dengan eksekusi query.

Implementasi Prepared Statement di DBMS

Prepared Statement sebenarnya adalah fitur di level DBMS. Masing-masing DBMS menyediakan cara untuk melakukan Prepared Statement. Framework (dan connector untuk setiap DBMS) kemudian melakukan wrapping terhadap prosedur tersebut.

Misal kita memiliki tabel tabelku dengna struktur sebagai berikut:

Sebuah query untuk mendapatkan data dengan id tertentu dapat ditulis sebagai berikut “SELECT a, b, c FROM tabelku WHERE id = ?”

Kita akan membuat sebuah Prepared Statement dan merujuknya sebagai stmt1. Eksekusi query selanjutnya akan menggunakan referensi stmt1.

PREPARE stmt1 FROM ‘SELECT a, b, c FROM tabelku WHERE id = ?’;

Sekarang misalkan kita ingin mendapatkan data dengan id = 1, maka query yang kita lakukan adalah:

Kita mendeklarasikan sebuah variabel @id bernilai ‘1’ menggunakan SET. Selanjutnya kita ke tahap Execute dimana kita mengeksekusi template stmt1 dengan nilai @id. Sekarang, bagaimana bila @id bernilai payload SQL injection?.

Kita akan coba mengisikan id dengan 135' OR ‘1’=’1 dimana 135 adalah id yang tak ada di tabel. Pertanyaannya adalah, apakah kriteria OR ‘1’=’1 akan tereksekusi dan menghasilkan TRUE sehingga query akan memberikan data?

Rupanya tidak!

Sebagai perbandingan, ini adalah data yang dihasilkan jika SQL injection terjadi dan query berubah menjadi seperti ini:

Jadi, apakah Prepared Statement sudah cukup? Silahkan bereksplorasi.

--

--