Ketika datang ke kueri database, selalu coba dan gunakan kueri berparameter yang disiapkan. The mysqli
dan PDO
perpustakaan mendukung ini. Ini jauh lebih aman daripada menggunakan fungsi pelolosan seperti mysql_real_escape_string
.
Ya, mysql_real_escape_string
secara efektif hanya fungsi pelarian string. Ini bukan peluru ajaib. Yang akan dilakukannya hanyalah melarikan diri dari karakter berbahaya agar dapat digunakan dengan aman dalam satu string kueri. Namun, jika Anda tidak membersihkan input Anda sebelumnya, maka Anda akan rentan terhadap vektor serangan tertentu.
Bayangkan SQL berikut ini:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Anda harus dapat melihat bahwa ini rentan untuk dieksploitasi.
Bayangkan id
parameter yang berisi vektor serangan umum:
1 OR 1=1
Tidak ada karakter berisiko di sana untuk dikodekan, jadi itu akan melewati filter melarikan diri. Meninggalkan kami:
SELECT fields FROM table WHERE id= 1 OR 1=1
Yang merupakan vektor injeksi SQL yang bagus dan akan memungkinkan penyerang mengembalikan semua baris. Atau
1 or is_admin=1 order by id limit 1
yang menghasilkan
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Yang memungkinkan penyerang mengembalikan detail administrator pertama dalam contoh yang sepenuhnya fiksi ini.
Meskipun fungsi-fungsi ini berguna, mereka harus digunakan dengan hati-hati. Anda perlu memastikan bahwa semua masukan web divalidasi sampai tingkat tertentu. Dalam hal ini, kami melihat bahwa kami dapat dieksploitasi karena kami tidak memeriksa bahwa variabel yang kami gunakan sebagai angka, sebenarnya numerik. Dalam PHP Anda harus banyak menggunakan serangkaian fungsi untuk memeriksa bahwa input adalah integer, float, alfanumerik, dll. Tetapi ketika datang ke SQL, perhatikan sebagian besar nilai dari pernyataan yang disiapkan. Kode di atas akan aman jika itu adalah pernyataan yang disiapkan karena fungsi database akan tahu bahwa 1 OR 1=1
itu bukan literal yang valid.
Adapun htmlspecialchars()
. Itu adalah ladang ranjau miliknya sendiri.
Ada masalah nyata dalam PHP karena ia memiliki seluruh pilihan fungsi pelolosan terkait html yang berbeda, dan tidak ada panduan yang jelas tentang fungsi mana yang melakukan apa.
Pertama, jika Anda berada di dalam tag HTML, Anda benar-benar dalam masalah. Melihat
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Kita sudah berada di dalam tag HTML, jadi kita tidak perlu <atau> melakukan sesuatu yang berbahaya. Vektor serangan kami mungkin sajajavascript:alert(document.cookie)
Sekarang HTML yang dihasilkan terlihat seperti
<img src= "javascript:alert(document.cookie)" />
Serangan itu langsung masuk.
Lebih buruk. Mengapa? karena htmlspecialchars
(jika disebut demikian) hanya menyandikan tanda kutip ganda dan tidak tunggal. Jadi jika kita punya
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Penyerang jahat kami sekarang dapat memasukkan parameter baru
pic.png' onclick='location.href=xxx' onmouseover='...
memberi kami
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
Dalam kasus ini, tidak ada peluru ajaib, Anda hanya perlu menyesuaikan masukannya sendiri. Jika Anda mencoba dan menyaring karakter jahat, Anda pasti akan gagal. Ambil pendekatan daftar putih dan biarkan melalui karakter yang bagus. Lihatlah lembar contekan XSS untuk contoh tentang betapa beragamnya vektor
Bahkan jika Anda menggunakan di htmlspecialchars($string)
luar tag HTML, Anda masih rentan terhadap vektor serangan charset multi-byte.
Cara yang paling efektif adalah menggunakan kombinasi mb_convert_encoding dan htmlentities sebagai berikut.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Bahkan ini membuat IE6 rentan, karena cara menangani UTF. Namun, Anda dapat kembali ke pengkodean yang lebih terbatas, seperti ISO-8859-1, hingga penggunaan IE6 berhenti.
Untuk studi yang lebih mendalam tentang masalah multibyte, lihat https://stackoverflow.com/a/12118602/1820