Learning All About Hacks Blog — SQL Injection — Structured Query Language (SQL) digunakan untuk melakukan query, mengoperasikan, dan mengelola sistem database seperti SQL server, Oracle, atau MySQL.
Penggunaan umum SQL konsisten di semua sistem databatase, namun ada detail perbedaan tertentu yang khusus untuk setiap sistem.
SQL Injection adalah teknik yang menyalahgunakan celah keamanan yang ada pada lapisan basis data sebuah aplikasi. Celah ini terjadi ketika input dari pengguna tidak disaring secara benar.
Contohnya adalah kolom username yang seharusnya hanya diisi dengan huruf atau angka tapi malah diisi dengan karakter lain (seperti: – = ’) sehingga penyerang menggunakan celah tersebut dengan cara memasukan query dari SQL.
Injeksi SQL (Bahaasa Inggris: SQL Injection)adalah sebuah teknik yang menyalahgunakan sebuah celah keamanan yang terjadi dalam lapisan basis data sebuah aplikasi. Celah ini terjadi ketika masukan pengguna tidak disaring secara benar dari karakter-karakter pelolos bentukan string yang diimbuhkan dalam pernyataan SQL atau masukan pengguna tidak bertipe kuat dan karenanya dijalankan tidak sesuai harapan.
Ini sebenarnya adalah sebuah contoh dari sebuah kategori celah keamanan yang lebih umum yang dapat terjadi setiap kali sebuah bahasa pemrograman atau skrip diimbuhkan di dalam bahasa yang lain.
Karakter-karakter pelolos yang tidak disaring secara benar
Ini menimbulkan potensi untuk memanipulasi pernyataan-pernyataan yang dilakukan pada basis data oleh pengguna akhir aplikasi.
Baris kode berikut menggambarkan celah keamanan ini:
pernyataan:= "SELECT * FROM pengguna WHERE nama = '" + namaPengguna + "';"
Jika variabel "namaPengguna" dirangkai sedemikian rupa oleh pengguna yang bermaksud buruk, pernyataan SQL tersebut bisa melakukan lebih daripada yang pengarangnya maksudkan. Sebagai contoh, mengeset variabel "namaPengguna" sebagai
a' or 't'='t
menjadikan pernyataan SQL ini oleh bahasa yang memuatnya:
SELECT * FROM pengguna WHERE nama = 'a' or 't'='t';
Jika kode ini akan digunakan dalam sebuah prosedur untuk melakukan otentikasi, maka contoh ini dapat dipakai untuk memaksakan pemilihan sebuah nama pengguna yang sah karena evaluasi 't'='t' akan selalu bernilai benar.
Secara teori, perintah SQL sah apapun bisa diinjeksi melalui metode ini, termasuk menjalankan banyak pernyataan. Nilai "namaPengguna" berikut ini pada pernyataan di atas akan menyebabkan dihapusnya tabel "pengguna" dan juga pengambilan semua data dari tabel "data":
a';DROP TABLE pengguna; SELECT * FROM data WHERE nama LIKE '%
Masukan ini menjadikan pernyataan akhir SQL sebagai berikut:
SELECT * FROM pengguna WHERE nama = 'a';DROP TABLE pengguna; SELECT * FROM data WHERE nama LIKE '%';
Penanganan tipe yang tidak benar
pernyataan:= "SELECT * FROM data WHERE id = " + variabel_a + ";"
Terlihat jelas dari pernyataan ini pengarang memaksudkan variabel_a menjadi sebuah nomor yang berhubungan dengan unsur "id". Namun begitu, jika pada kenyataannya itu adalah sebuah string, maka pengguna akhir dapat memanipulasi pernyataan tersebut sesukanya, dan karena itu mengabaikan kebutuhan akan karakter-karakter pelolos. Sebagai contoh, mengeset variabel_a sebagai
1;DROP TABLE pengguna
akan menghapus tabel "pengguna" dari basis data karena hasil akhir SQL-nya akan menjadi sebagai berikut:
SELECT * FROM data WHERE id = 1;DROP TABLE pengguna;
Celah keamanan dalam server basis data
Perbaikan aplikasi
$kueri = $sql->prepare
(
"select * from pengguna where nama = "
.
$sql->quote($nama_pengguna)
);
Namun begitu, secara umum ini bukan jalan yang terbaik dalam menghadapi masalah tersebut. DBI mengizinkan penggunaan placeholder, yang memperbolehkan Anda untuk mengikat data ke sebuah pernyataan secara terpisah dari pendefinisian pernyataan SQL tersebut. Untuk sistem basis data yang tidak secara asli mendukung placeholder.
DBI menirukannya dengan menggunakan fungsi DBI::quote secara otomatis pada nilai-nilai. Banyak sistem basis data yang mendukung pengikatan nilai secara terpisah melalui API mereka; DBI akan menggunakan dukungan placeholder asli tersebut dalam hal ini. Sebagai contoh:
$kueri = $sql->prepare("select * from pengguna where nama = ?");
$kueri->execute($nama_pengguna);
Keuntungannya adalah Anda tidak perlu mengingat untuk menggunakan DBI::quote kepada setiap nilai. Nilai-nilai akan diikat secara terpisah, atau dikutip secara benar, tergantung pada dukungan yang ditawarkan oleh SMBD tertentu yang Anda gunakan. Anda kemudian terhindari dari masalah dasar injeksi SQL di mana nilai-nilai diinterpretasi sebagai SQL.
Bagi sistem basis data yang mendukung placeholder secara asli, sering kali ada keuntungan kinerja yang nyata untuk menggunakan placeholder, karena basis data dapat menyimpan cache dari sebuah perwakilan pernyataan yang terkompilasi dan menggunakannya secara berulang di antara pelaksanaan-pelaksanaan dengan nilai-nilai ikatan yang berbeda. Placeholder kadang-kadang juga disebut sebagai "variabel pengikat".
Dalam PHP, terdapat beberapa fungsi bawaan yang berbeda untuk digunakan pada SMBD-SMBD yang berbeda untuk meloloskan nilai-nilai yang cocok untuk diimbuhkan dalam pernyataan-pernyataan SQL harafiah. Untuk MySQL, yang serupa dengan ini adalah fungsi bawaan mysql_real_escape_string:
$hasil_kueri = mysql_query ( "select * from pengguna where nama = '" . mysql_real_escape_string($nama_pengguna) . "'" );
Antarmuka asli untuk sebuah SMBD tertentu dapat juga menawarkan sebuah metode untuk melakukan pengikatan placeholder secara terpisah, misalnya mysql_stmt_bind_param atau oci_bind_by_name.
Selain itu, sebuah pustaka abstraksi basis data dapat digunakan untuk menirukan placeholder dalam cara yang mirip dengan DBI dari Perl. Sebuah contoh dari beberapa pustaka yang ada ialah ADOdb.
Dalam bahasa pemrograman Java, yang serupa adalah kelas PreparedStatement.
Dari pada
Connection con = (peroleh koneksi) Statement stmt = con.createStatement(); ResultSet rset = stmt.executeQuery("SELECT * FROM pengguna WHERE nama = '" + userName + "';");
Gunakan yang berikut
Connection con = (peroleh koneksi) PreparedStatement pstmt = con.prepareStatement("SELECT * FROM pengguna WHERE nama = ?"); pstmt.setString(1, namaPengguna); ResultSet rset = pstmt.executeQuery();
Dalam bahasa pemrograman "C#" .NET atau Mono, yang serupa adalah objek-objek ADO.NET SqlCommand (untuk Microsoft SQL Server) atau OracleCommand (untuk server basis data Oracle).
Contoh di bawah ini memperlihatkan bagaimana mencegah serangan injeksi menggunakan objek SqlCommand. Kode untuk penyedia ADO.NET lainnya sangat mirip, tetapi dapat sedikit berbeda tergantung pada implementasi khusus yang dibuat oleh vendor penyedia tersebut.
Dari pada
using( SqlConnection con =
(peroleh koneksi) ) { con.Open();
using( SqlCommand cmd =
new SqlCommand("SELECT * FROM pengguna WHERE nama =
'" + namaPengguna + "'", con) )
{ using( SqlDataReader rdr = cmd.ExecuteReader() ) { ...
}
}
}
Gunakan yang berikut
using( SqlConnection con =
(peroleh koneksi) ) { con.Open(); using( SqlCommand cmd =
new SqlCommand("SELECT * FROM users WHERE name =
@namaPengguna", con) )
{ cmd.Parameters.AddWithValue("@namaPengguna", namaPengguna);
using( SqlDataReader rdr = cmd.ExecuteReader() ) { ...
}
}
}
Perbaikan basis data
Kebanyakan basis data juga menawaran kemampuan untuk menyiapkan pernyataan-pernyataan SQL pada lapisan basis data melalui stored procedure. Daripada menggunakan sebuah lapisan aplikasi untuk merangkai SQL secara dinamis, stored procedure membungkus prosedur-prosedur basis data pakai-ulang yang dipanggil dengan parameter-parameter bertipe.
Ini menyediakan beberapa keuntungan keamanan dengan membuat masukan-masukan menjadi parameter dan mewajibkan tipe pada mereka, masukan pengguna secara efektif tersaring. Sebagai tambahan, kebanyakan basis data mengizinkan stored procedure untuk berjalan di bawah hak-hak keamanan yang berbeda daripada pengguna basis data.
Misalnya, sebuah aplikasi akan memiliki akses untuk menjalankan sebuah stored procedure, tetapi tidak memiliki akses ke tabel-tabel dasarnya. Ini membatasi kemampuan aplikasi untuk melakukan sesuatu yang di luar aksi-aksi yang dituliskan di dalam stored procedure.
Yang juga penting untuk dicatat adalah metode kueri standar dari pustaka client C MySQL tidak akan mengizinkan lebih daripada sebuah kueri dalam sebuah masukan, mencegah serangan banyak-pernyataan yang dipaparkan di atas. Namun begitu, masukan pengguna baik-baik yang mengandung karakter-karakter pelolos (misalnya tanda kutip tunggal) tetap dapat menyebabkan aplikasi tidak berjalan karena sintaks SQL yang buruk.
Bahkan beberapa serangan juga mungkin terjadi, sebagai contoh misalkan sebuah situs web yang memperlihatkan sebuah daftar barang untuk sebuah nama pengguna yang dikenal. Kueri yang dijalankan adalah:
SELECT * from barang where namapengguna='$namapengguna';
Seorang penyerang dapat memakai nama pengguna yang dirangkai secara khusus untuk mengetahui semua barang milik semua pengguna:
$namapengguna = "' or namapengguna is not null or namapengguna='";
Menghasilkan pernyataan SQL sebagai berikut:
SELECT * from barang where namapengguna='' or namapengguna is not null or namapengguna='';
Ingatlah, walaupun begitu, bahwa meloloskan atau menghapus tanda kutip tidak melenyapkan risiko injeksi SQL sepenuhnya. Misalkan kueri Anda tampak seperti ini:
SELECT * from barang where idpengguna=$idpengguna;
Dengan anggapan bahwa $idpengguna merupakan nilai numerik tetapi dibiarkan lolos tanpa diperiksa, idpengguna yang dirangkai khusus ini akan, sekali lagi, memperlihatkan semua barang milik semua pengguna:
$idpengguna = "33 or idpengguna is not null or userid=44";
Yang seperti dapat Anda lihat, tidak mengandung tanda kutip sama sekali dan akan menghasilkan kueri ini:
SELECT * from barang where idpengguna=33 or idpengguna is not null or idpengguna=44;
Pertahanan yang terbaik, daripada membuat daftar hitam masukan buruk yang diketahui, adalah hanya mengizinkan masukan baik yang diketahui, atau, dengan kata lain, membuat daftar putih.
Misalnya, jika Anda ingin bertahan terhadap serangan ini, Anda dapat memeriksa variabel idpengguna untuk memastikan bahwa isinya numerik seperti berikut:
if(!ctype_digit($idpengguna)){ die("Karakter-karakter yang tidak sah dalam idpengguna."); }
SQL Injection selalu menjadi teknik penyerangan terfavorit sebagian besar hacker dari tahun ke tahun, disamping karena semakin sulitnya hacker melakukan serangan melalui jaringan yang disebabkan oleh semakin canggihnya perangkat-perangkat pertahanan dari target.
Contoh: (firewall, IDS, UTM, dll), SQL Injection juga sangat mudah dilakukan karena masih banyak web programmer yang masih kurang “aware” terhadapnya.
Meskipun efek dari SQL Injection bervariasi berdasarkan aplikasi yang ditargetkan, namun secara umum SQL Injection bertujuan:
#Otentikasi Bypass
Serangan ini memungkinkan penyerang untuk masuk ke dalam aplikasi dengan hak akses administratif, tanpa menggunakan username dan password yang valid.#Pencurian Informasi
Serangan ini memungkinkan penyerang untuk mendapatkan, baik secara langsung maupun tidak langsung informasi-informasi sensitif di dalam database.#Compromised Integritas Data
Serangan ini melibatkan perubahan isi database, seorang penyerang bisa menggunakan serangan ini untuk deface halaman web atau memasukkan konten berbahaya ke dalam halaman web.#Compromised Ketersediaan Data
Serangan ini memungkinkan penyerang untuk menghapus informasi dengan maksud untuk merusak atau menghapus log atau audit informasi dalam database.#Remote Command Execution:
Melakukan perintah eksekusi melalui database yang memungkinkan penyerang untuk melakukan compromise pada sistem operasi host atau target.Satu dari banyak penggunaan SQL Injection melibatkan bypass pada sebuah proses autentikasi login aplikasi, umumnya form login username dan password pada memiliki konstruksi SQL Query seperti ini:
Otentikasi biasa:
SELECT count (*) FROM Users WHERE Username=’Ronaldo’ AND Password= ‘Butterfly’
Otentikasi yang dilakukan attacker:
SELECT count (*) FROM Users WHERE Username=’qwert’ or 1=1 — ’ AND Password= ‘zxcvb’
Input yang masuk ke database seharusnya berisikan username (Ronaldo) dan password (Butterfly). Input yang dimasukkan attacker “qwert” di form email tidaklah penting karena setelah itu ada tanda “or 1=1 — “ dimana artinya setiap input akan selalu dianggap true.
Karena 1=1adalah alias dari true dan or adalah kondisi dimana jika ada salah 1 atau lebih dari 2 atau lebih input true maka otentikasi akan dianggap true oleh sistem. dan form password pun bisa diisi sesuka hati karena dibelakang tanda “– “ itu hanya dianggap sebagai syntax comment pada SQL.
Berikut merupakan contoh source code yang memiliki celah untuk terkena sql injection, pada bagian request.get Parameter data yang diterima SQL query dikirim langsung dari HTTP request tanpa validasi dari data tersebut (jumlah min/max karakter, jenis karakter yang diizinkan atau karakter-karakter berbahaya). Kesalahan ini menimbulkan celah untuk menjadikan SQL sebagai payload dan mengubah fungsi statement yang ada.
String DRIVER = “com.ora.jdbc.Driver”;
String DataURL = “jdbc:db://localhost:5112/users”;
String LOGIN = “admin”;
String PASSWORD = “admin123”;
Class.forName(DRIVER);
//Make connection to DB
Connection connection = DriverManager.getConnection(DataURL, LOGIN, PASSWORD);
String Username = request.getParameter(“USER”); // From HTTP request
String Password = request.getParameter(“PASSWORD”); // From HTTP request
int iUserID = -1;
String sLoggedUser = “”;
String sel = “SELECT User_id, Username FROM USERS WHERE Username = ‘” +Username + “‘ AND Password = ‘” + Password + “‘”;
Statement selectStatement = connection.createStatement ();
ResultSet resultSet = selectStatement.executeQuery(sel);
if (resultSet.next()) {
iUserID = resultSet.getInt(1);
sLoggedUser = resultSet.getString(2);
}
PrintWriter writer = response.getWriter ();
if (iUserID >= 0) {
writer.println (“User logged in: ” + sLoggedUser);
} else {
writer.println (“Access Denied!”)
Mempelajari SQL sangat penting untuk melakukan serangan SQL Injection, namun ada cukup banyak juga tools serangan otomatis untuk melakukan SQL Injection.
Sebagai web programmer kita harus mempelajari bagaimana cara melakukan secure programmer, tidak hanya dalam web programming tetapi juga dalam berbagai bahasa programming lainnya.
Pembelajaran lebih lanjut tentang SQL Injection dapat dipelajari di kelas Certified Ethical Hacker (CEH) yang diadakan oleh EC-Council, dan jika ingin mempelajari lebih lanjut tentang Secure Programming maka EC-Council juga menyediakan training EC-Council Certified Secure Programmer (ECSP) yang memiliki pilihan kelas, .Net atau Java.