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
$result = "SELECT fields FROM table WHERE id = '".mysql_real_escape_string($_POST['id'])."'";
2. Dalam kasus kedua (atribut berisi URL), tidak ada gunanyahtmlspecialchars
sama sekali; dalam kasus ini, Anda harus menyandikan masukan menggunakan skema pengkodean URL, misalnya, menggunakanrawurlencode
. Dengan cara itu, pengguna tidak dapat memasukkanjavascript:
et al.Take a whitelist approach and only let through the chars which are good.
Daftar hitam akan selalu melewatkan sesuatu. +1Selain jawaban bagus Cheekysoft:
Sebenarnya tidak ada solusi ampuh untuk mencegah injeksi HTML (mis. Pembuatan skrip lintas situs), tetapi Anda mungkin dapat mencapainya dengan lebih mudah jika Anda menggunakan pustaka atau sistem template untuk menghasilkan HTML. Baca dokumentasi untuk itu tentang bagaimana melarikan diri dengan tepat.
Dalam HTML, hal-hal perlu di-escape secara berbeda tergantung pada konteksnya. Hal ini terutama berlaku untuk string yang ditempatkan ke Javascript.
sumber
Saya pasti setuju dengan posting di atas, tetapi saya memiliki satu hal kecil untuk ditambahkan sebagai balasan atas jawaban Cheekysoft, yaitu:
Saya membuat kode fungsi kecil cepat yang saya masukkan ke kelas database saya yang akan menghapus apa pun yang bukan angka. Ini menggunakan preg_replace, jadi ada kemungkinan fungsi yang sedikit lebih dioptimalkan, tetapi berfungsi dalam keadaan darurat ...
Jadi, alih-alih menggunakan
Saya akan menggunakan
dan itu akan menjalankan kueri dengan aman
Tentu, itu hanya menghentikannya dari menampilkan baris yang benar, tapi saya rasa itu bukan masalah besar bagi siapa pun yang mencoba menyuntikkan sql ke situs Anda;)
sumber
return preg_match('/^[0-9]+$/',$input) ? $input : 0;
Bagian penting dari teka-teki ini adalah konteks. Seseorang yang mengirimkan "1 OR 1 = 1" sebagai ID tidak menjadi masalah jika Anda mengutip setiap argumen dalam kueri Anda:
Yang mengakibatkan:
yang tidak efektif. Karena Anda keluar dari string, input tidak dapat keluar dari konteks string. Saya telah menguji ini sejauh versi 5.0.45 dari MySQL, dan menggunakan konteks string untuk kolom integer tidak menimbulkan masalah.
sumber
Bekerja dengan baik, bahkan lebih baik pada sistem 64 bit. Waspadalah terhadap batasan sistem Anda dalam menangani jumlah besar, tetapi untuk id database ini berfungsi dengan baik 99% dari waktu.
Anda harus menggunakan satu fungsi / metode untuk membersihkan nilai-nilai Anda juga. Meskipun fungsi ini hanya pembungkus untuk mysql_real_escape_string (). Mengapa? Karena suatu hari ketika eksploitasi ke metode pembersihan data pilihan Anda ditemukan, Anda hanya perlu memperbaruinya di satu tempat, daripada mencari dan mengganti di seluruh sistem.
sumber
mengapa, oh MENGAPA, Anda tidak akan menyertakan tanda kutip di sekitar input pengguna dalam pernyataan sql Anda? tampaknya cukup konyol untuk tidak melakukannya! memasukkan tanda kutip dalam pernyataan sql Anda akan membuat "1 atau 1 = 1" usaha yang sia-sia, bukan?
jadi sekarang, Anda akan berkata, "bagaimana jika pengguna menyertakan kutipan (atau tanda kutip ganda) di input?"
baik, perbaikan mudah untuk itu: cukup hapus kutipan yang dimasukkan pengguna. mis
input =~ s/'//g;
. : . sekarang, menurut saya, input pengguna itu akan diamankan ...sumber