Lapisan abstraksi database seperti Portable Data Objects (PDO) PHP bukanlah konsep baru, tetapi banyak pengembang tampaknya tidak menyadari manfaat keamanan yang mereka dapatkan secara gratis dengan menggunakannya – perlindungan yang melekat terhadap injeksi SQL.
Injeksi SQL adalah buffer overflow dari dunia aplikasi web – sudah ada selamanya, dan setiap pengembang aplikasi web harus tahu cara menulis kode aman yang tidak rentan terhadapnya. Bagi mereka yang tidak tahu, injeksi SQL adalah teknik di mana penyerang jahat dapat mengeksploitasi validasi data yang tidak memadai untuk menyuntikkan kode SQL arbitrer ke dalam kueri aplikasi Anda dan menjalankannya seolah-olah itu adalah kueri yang sah. Saya tidak akan membahas terlalu dalam tentang injeksi SQL di artikel ini, tetapi berikut adalah contoh sederhana:
Halaman depan aplikasi Anda memiliki formulir login, yang dikirimkan ke skrip PHP untuk memvalidasi kredensial pengguna dan mengizinkan atau menolak akses ke aplikasi. Formulir login mengirimkan dua variabel dengan POST sebagai berikut:
username = fred & password = Fr3dRul3z
Data POST kemudian digunakan untuk membuat kueri SQL untuk memvalidasi kredensial, seperti ini:
$ sql = “PILIH * DARI pengguna DI MANA username = ‘”. $ _ PERMINTAAN[‘username’]. “‘AND password ='”. $ _ REQUEST[‘password’]. “‘”;
Ini akan menghasilkan kueri SQL:
PILIH * FROM users WHERE username = ‘fred’ AND password = ‘Fr3dRul3z’
Dengan asumsi baris ada dalam database dengan kredensial ini, pengguna akan diizinkan untuk masuk. Penyerang dapat dengan mudah menghindari skema otentikasi ini dengan keluar dari bidang nama pengguna ke dalam kueri SQL dengan tidak memasukkan apa pun ke bidang sandi dan ini ke dalam bidang nama pengguna:
‘ATAU 1 == 1 –
String kueri SQL yang dihasilkan akan terlihat seperti ini:
PILIH * DARI pengguna DIMANA nama pengguna = ‘fred’ ATAU 1 == 1 – ‘DAN kata sandi =’ ‘
Yang, seperti yang saya yakin Anda bisa lihat, akan memilih semua pengguna dari database karena kondisi 1 == 1 akan selalu benar. Sisa kueri akan dibuang dengan operator komentar ‘-‘. Cara untuk menghindari serangan semacam ini adalah dengan membersihkan data yang dikirimkan ke formulir dengan melarikan diri dari segala sesuatu yang dapat digunakan untuk keluar dari batasan tanda kutip di sekitar bidang (misalnya mysql_real_escape_string () jika Anda menggunakan MySQL). Namun, di negeri yang jauh seseorang menemukan lapisan abstraksi database …
Tujuan utama dari lapisan abstraksi database seperti PDO adalah abstraksi bersih dalam kode Anda jauh dari platform database – jadi, secara teoritis, Anda dapat beralih platform database dari, katakanlah, MySQL ke PostgreSQL atau Oracle dengan sedikit perubahan pada kode. Dalam praktiknya, ini sangat bergantung pada seberapa besar kode Anda bergantung pada fitur khusus platform seperti pemicu dan prosedur tersimpan, tetapi jika Anda tidak mengandalkannya sama sekali dan Anda hanya melakukan operasi INSERT / UPDATE / DELETE sederhana, ini adalah perjalanan gratis . Kedengarannya cukup berguna, tapi tidak ada yang menarik, bukan? Baik. Fitur rapi lainnya yang ditemukan sejak lama adalah pernyataan yang disiapkan, dan sebagian besar lapisan abstraksi database (termasuk PDO) mengimplementasikannya sebagai cara untuk melakukan kueri yang sama beberapa kali dengan kumpulan data yang berbeda (misalnya, memasukkan sejumlah besar baris baru). Sekarang, saat membuat pernyataan dengan PDO, alih-alih membuat string SQL secara manual seperti yang ditunjukkan sebelumnya, kami membuat pernyataan dengan placeholder seperti ini:
$ sql = “MASUKKAN KE buah-buahan (nama, harga) NILAI (?,?)”;
lalu jalankan kueri dengan kumpulan data yang diteruskan ke lapisan abstraksi sebagai berikut:
$ sth = $ dbh-> siapkan ($ sql);
$ sth-> mengeksekusi (array ($ buah, $ harga));
Ketika data diserahkan ke PDO seperti ini, data akan diteruskan ke driver database secara langsung, atau membuat kueri secara internal dengan cara yang aman dengan data yang berpotensi berbahaya dikodekan atau lolos. Seperti yang Anda lihat, ini adalah cara mudah mengatasi masalah injeksi SQL.
Namun, pernyataan yang disiapkan dengan PDO tidak semuanya anak anjing dan pelangi. Menggunakan pernyataan yang sudah disiapkan dapat memperkenalkan sejumlah peringatan menarik yang harus diperhatikan oleh pengembang. Misalnya, dalam pernyataan yang disiapkan API klien MySQL tidak dapat mengeksekusi jenis kueri tertentu[1] dan mereka tidak menggunakan cache kueri[1][2] yang mungkin berdampak pada kinerja aplikasi Anda.
Keamanan inheren dalam menggunakan pernyataan yang telah disiapkan kedengarannya bagus, tetapi pengembang tidak boleh membiarkan PDO dan lapisan abstraksi lainnya / implementasi pernyataan siap membuai mereka ke dalam rasa aman yang palsu. Data yang tidak tepercaya harus selalu divalidasi dan disterilkan, PDO hanyalah garis pertahanan lainnya. Ini tidak mencakup wilayah banyak kerentanan validasi input lainnya seperti skrip lintas situs, tetapi berfungsi dengan baik dalam melindungi aplikasi dari injeksi SQL. Strategi terbaik hanya mengizinkan data bagus yang diketahui dengan memasukkan karakter ke dalam daftar putih dan mencocokkan data masukan dengan pola ekspresi reguler, kemudian menggunakan pernyataan yang disiapkan untuk menangkap apa pun yang bijaksana injeksi SQL yang tidak dilewatkan oleh validasi masukan, semua dalam hubungannya dengan firewall aplikasi web seperti ModSecurity.
PDO telah dibangun di PHP sejak versi 5.1.0, yang dirilis pada November 2005. Kecuali Anda punya alasan kuat untuk tidak menggunakannya di aplikasi PHP Anda, Anda harus – ini adalah pengganti portabel untuk mysql_ lama * fungsi dan fungsi khusus platform lainnya dengan manfaat tambahan perlindungan terhadap injeksi SQL.