it-swarm-id.com

Injeksi SQL - mengapa tidak melarikan diri dari kutipan aman lagi?

SQL mentah

Ketika Anda menulis SQL - untuk apa pun yang benar-benar membutuhkan input manusia, banyak hal telah dilakukan untuk menghindari injeksi.

Semua orang yang mendengar injeksi SQL tahu bahwa (saya akan menggunakan PHP sebagai contoh) melakukan sesuatu seperti ini tidak aman:

$sql = "SELECT * FROM `users` 
.  WHERE `userName` = "{$_POST["username"]}" 
.  AND `pass` = "{$_POST["pass"]}";";

Sihir

Kemudian tentu saja, seseorang keluar dengan ide menggunakan "kutipan pelarian sulap" untuk menangani input program yang tidak dibersihkan dengan benar dan langsung dimasukkan ke dalam sql sebagai akibat dari praktik buruk. Ini tidak benar-benar menyelesaikan masalah dengan injeksi SQL, tetapi itu berarti semua input pengguna rusak.

Menambahkan garis miring

Jadi, beberapa orang mematikan kutipan sihir. Kemudian, mereka mem-parsing input pengguna sebelum titik SQL melalui addslashes() yang secara teori lolos dari semua kuotasi dan hacker Anda tidak dapat melakukan ' OR 1=1, Tetapi bahkan dokumentasi untuk addlashes itu sendiri mengatakan bahwa Anda seharusnya tidak menggunakan addlashes, katanya gunakan fungsi spesifik basis data seperti mysql_real_escape_string(), tetapi ini masih dikatakan tidak cukup oleh beberapa orang.

Menambahkan garis miring khusus ke Database

Jadi, kita tidak bisa menggunakan DBMS spesifik *_real_escape_string, Kita tidak bisa menggunakan add slashes, Hal "kutipan ajaib" menyebabkan banyak masalah, dan web penuh dengan kutipan kata-kata pendek seperti :

"Seorang hacker yang berdedikasi akan menemukan cara untuk melompati loop kutipan-melarikan diri Anda, cukup gunakan pernyataan yang disiapkan DBAL" - John Q programmer mana pun

Oke, jadi itu cukup membuatku takut untuk menggunakan pernyataan persiapan dan DBAL. Itu tidak benar-benar menjelaskan apa-apa, tetapi kedengarannya bagus karena saya sudah sering mendengarnya.

Pernyataan yang disiapkan

Jadi sekarang kita menggunakan PDO, atau DBAL dari framework, atau sesuatu yang membungkus semua sql kita dan memastikan seseorang tidak dapat menjalankan injeksi sql.

Pertanyaan saya pada dasarnya adalah "mengapa tidak?", Bukan "apa yang harus saya gunakan?". Web penuh dengan orang yang memberitahu Anda untuk menggunakan ini atau menggunakannya atau apa pun , tetapi tidak ada penjelasan mengapa hal-hal ini harus terjadi.

Pertanyaan langsung

Menunjuk pertanyaan (pengingat, saya bertanya tentang SQL, PHP adalah contoh bahasa karena itu reputasi buruk di SQL, konsep universal):

  1. Mengapa kita tidak bisa lepas dari semua input pengguna menggunakan "sihir"?
  2. Mengapa addlashes tidak "cukup baik"?
  3. Apa yang salah dengan menggunakan fungsi pelarian khusus DB, dan mengapa lebih baik daripada addlashes?
  4. Mengapa pernyataan yang disiapkan dengan kerangka kerja dan PDO dipuji sebagai standar emas SQL? Mengapa mereka lebih baik? Mengapa saya tidak bisa melakukan injeksi SQL dengan ini, sedangkan saya BISA dengan cara yang disebutkan sebelumnya? Bisakah seorang programmer tidak entah bagaimana masih bisa mengacaukan ini? Apa yang harus mereka waspadai?
  5. Ada masalah lain yang belum saya kemukakan?
78
Incognito

Mengapa kita tidak bisa lepas dari semua input pengguna menggunakan "sihir"?

Pada saat keajaiban diterapkan, tidak diketahui di mana data akan berakhir. Jadi kutipan ajaib menghancurkan data itu, kecuali jika dituliskan tanpa terhapus ke database.

Ini hanya dapat digunakan dalam respons HTML yang dikirim kembali ke klien. Pikirkan formulir yang belum diisi sepenuhnya dan karenanya ditampilkan lagi kepada pengguna. Dengan kutipan ajaib, data yang dimasukkan pada upaya pertama sekarang akan menjadi SQL yang lolos, yang tidak ada artinya pada halaman HTML. Lebih buruk lagi: pada pengajuan kedua data SQL lolos lagi.

Mengapa addlashes tidak "cukup baik"?

Ini memiliki masalah dengan karakter multibyte:

' 27
\ 5c
뼧 bf 5c

Itu adalah dua byte, tetapi hanya satu karakter Unicode.

Karena addslashes tidak tahu apa-apa tentang Unicode, itu mengubah input bf 27 hingga bf 5c 27. Jika ini dibaca oleh program Unicode-aware, ini dilihat sebagai 뼧 '. Ledakan.

Ada penjelasan yang bagus tentang masalah ini di http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

Apa yang salah dengan menggunakan fungsi pelarian khusus DB, dan mengapa lebih baik daripada addlashes?

Mereka lebih baik karena mereka memastikan bahwa pelarian menginterpretasikan data dengan cara yang sama seperti yang dilakukan database (lihat pertanyaan terakhir).

Dari sudut pandang keamanan, mereka boleh jika Anda menggunakannya untuk setiap input basis data tunggal. Tetapi mereka memiliki risiko bahwa Anda mungkin melupakan salah satu dari mereka di suatu tempat.

Edit : Seperti yang ditambahkan oleh getahobby: Atau Anda menggunakan xxx_escape_strings untuk angka tanpa menambahkan tanda kutip di sekitarnya dalam pernyataan SQL dan tanpa memastikan bahwa itu adalah angka aktual oleh casting atau mengonversi input ke tipe data yang sesuai /Edit

Dari perspektif pengembangan perangkat lunak mereka buruk karena mereka membuatnya jauh lebih sulit untuk menambahkan dukungan untuk perangkat lunak server database SQL lainnya.

Mengapa pernyataan yang disiapkan dengan kerangka kerja dan PDO dipuji sebagai standar emas SQL? Mengapa mereka lebih baik?

PDO sebagian besar merupakan hal yang baik untuk alasan desain perangkat lunak. Itu membuatnya jauh lebih mudah untuk mendukung perangkat lunak server database lainnya. Ini memiliki antarmuka berorientasi objek yang abstrak banyak ketidakcocokan spesifik database kecil.

Mengapa saya tidak bisa melakukan injeksi SQL dengan [pernyataan yang disiapkan] ini, di mana seperti yang saya BISA miliki dengan cara yang disebutkan sebelumnya?

Bagian " kueri konstan dengan parameter variabel " dari pernyataan yang disiapkan adalah yang penting di sini. Driver basis data akan lolos dari semua parameter secara otomatis tanpa pengembang harus memikirkannya.

Kueri parametrized seringkali lebih mudah dibaca yaitu kueri normal dengan parameter yang lolos karena alasan sintaksis. Tergantung pada lingkungannya, mereka mungkin sedikit lebih cepat.

Selalu menggunakan pernyataan yang disiapkan dengan parameter adalah sesuatu yang dapat divalidasi oleh alat analisis kode statis . Panggilan yang hilang ke xxx_escape_string tidak terlihat dengan mudah dan andal.

Bisakah seorang programmer tidak berhasil mengacaukan ini? Apa yang harus mereka waspadai?

"Pernyataan yang disiapkan" menyiratkan bahwa konstanta are . Secara dinamis menghasilkan pernyataan yang disiapkan - terutama dengan input pengguna - masih memiliki semua masalah injeksi.

52

[1.] Mengapa kita tidak bisa lepas dari semua input pengguna menggunakan "sihir"?

Karena kutipan sihir dipecah berdasarkan dua hal:

  1. Tidak semua data $ _ (REQUEST/GET/POST) masuk ke DB. Dan bagi Anda untuk membuatnya masuk akal, Anda harus melepaskan diri dari input.
  2. Mereka setara addslashes (lihat catatan saya di [2.]), karena itu mereka sebenarnya tidak aman.

[2.] Mengapa addlashes tidak "cukup baik"?

Ada banyak cara untuk keluar dari pembatasan addslashes, oleh karena itu, ini cacat secara fundamental, namun Anda mencoba menggunakannya.

[3.] Apa yang salah dengan menggunakan fungsi escape spesifik-DB, dan mengapa lebih baik daripada addlash?

Tidak ada yang benar-benar. Itu hanyalah mantra mengapa PDO/disiapkan "lebih baik". Mereka cara lebih baik daripada addslashes karena mereka menangani banyak faktor, termasuk penyandian. Ini sedikit rahasia; PDO menggunakannya secara internal, tetapi bukan addslashes...

[4.] Mengapa pernyataan disiapkan dengan kerangka kerja dan PDO dipuji sebagai standar emas SQL? Mengapa mereka lebih baik? Mengapa saya tidak bisa melakukan injeksi SQL dengan ini, sedangkan saya BISA dengan cara yang disebutkan sebelumnya?

Mereka bukan standar emas, mereka bukan "lebih" aman daripada fungsi spesifik DB dan Anda dapat melakukan injeksi SQL dengan ini demikian juga. Dan tidak, Anda tidak dapat melakukan injeksi SQL dengan input yang sudah dibersihkan dengan benar.

Seperti halnya semua teknologi di luar sana, pengembang cenderung mengembangkan kecenderungan keagamaan (fanatik?) Untuk sesuatu yang "baru". Itulah sebabnya Anda mendapatkan Zend Certified Engineers (TM) berpengalaman yang menasihati - tidak memaksa Anda untuk beralih ke pernyataan yang disiapkan.

Kenyataannya, semua itu tergantung pada mengetahui apa yang Anda lakukan. Jika Anda memuat artikel dengan ID numeriknya, Anda tidak perlu melarikan diri, apalagi PDO. Anda hanya perlu memastikan bahwa ID memang bilangan bulat.

Dari perspektif yang lebih realistis, aturan umum bukan untuk menggunakan PDO/pernyataan yang disiapkan, tetapi untuk menggunakan fungsi yang tepat, yaitu, Anda harus menggunakan mysql_real_escape_string() bukan bukannya addslashes() atau mysql_escape_string().

[5.] Bisakah seorang programmer tidak berhasil mengacaukannya? Apa yang harus mereka waspadai?

Tentu saja! Tapi itu bukan "apa yang harus diwaspadai" melainkan "tahu apa yang Anda lakukan".

Anda tahu, eval($_GET['code']) * sepenuhnya sah ketika digunakan di tempat yang tepat (seperti PHP Runner Test) lokal).

Jika Anda menggunakan ORM untuk menjalankan kueri bersyarat, Anda memasukkan kode secara langsung, maka ada kemungkinan mendapatkan injeksi SQL jika Anda tidak melakukannya dengan benar (tergantung pada ORM yang dimaksud). (Hipotetis) Contoh:

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(* Saya hanya bisa membayangkan profesional yang tak terhitung jumlahnya membenturkan kepala mereka atas hal ini)

13
Christian

Pada akhirnya melarikan diri dari input harus dilakukan untuk melindungi permintaan Anda dari SQL Injection. Pustaka query parametrized seperti PDO dan ADODB menggunakan escaping , semua yang mereka lakukan adalah menerapkan praktik ini dengan cara yang secara implisit aman. Dengan constrast magic_quotes_gpc tidak [~ # ~] bukan [~ # ~] , ini adalah pendekatan yang secara mendasar cacat pada masalah.

1) Lolos bisa bermasalah jika Anda tidak mengerti apa yang Anda lakukan. Jenis masalah ini masih dapat dieksploitasi jika magic_quotes_gpc diaktifkan.

mysql_query("select * from users where id=".addslashes($_GET[id]));

Eksploitasi PoC: http: //localhost/vuln.php? Id = sleep ( )

tambalan:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

Pelajaran: Anda tidak perlu tanda kutip untuk mengeksploitasi injeksi sql.

2) Katakanlah Anda hanya lolos tanda kutip:

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

Eksploitasi PoC: http: //localhost/vuln.php? Name = \& id = + atau + sleep (30)/*

Patch:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

Pelajaran : Garis miring terbalik sama berbahayanya sebagai tanda kutip.

3) Bagaimana dengan pengodean bahasa?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

Eksploitasi PoC: http: //localhost/vuln.php? Name =% bf% 27 = tidur (30)/*

Patch:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

Kesimpulan:

Escaping mutlak diperlukan untuk mencegah injeksi sql dalam suatu aplikasi. Dalam PHP PDO dan ADOB adalah pustaka permintaan parametrized yang bagus yang memaksa pelolosan input pengguna. Masalahnya adalah bahwa banyak programmer tidak mengerti apa itu pelarian. Memiliki perpustakaan untuk menegakkan kebijakan keamanan ini adalah metode pertahanan terbaik, karena Anda tidak perlu memahami aturan pelarian.

9
rook

Tentang fungsi pelarian khusus DB. Ada banyak skenario di mana injeksi SQL dapat terjadi, meskipun mysql_real_escape_string () telah digunakan. LIMIT dan ORDER BY benar-benar rumit!

Contoh-contoh itu rentan terhadap injeksi SQL:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
$sql = "SELECT userid, username FROM sql_injection_test LIMIT $offset, 10";

atau

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
$sql = "SELECT userid, username FROM sql_injection_test ORDER BY `$order`";

Dalam kedua kasus Anda tidak dapat menggunakan 'untuk melindungi enkapsulasi.

sumber : Injeksi SQL yang Tidak Terduga (Ketika Lolos Tidak Cukup) <- Baca ini

5
Cut Copy

Filter dapat di-bypass dan data yang masuk ke pernyataan SQL dapat berasal dari lebih banyak tempat daripada sekadar input pengguna. Titik masuk ke sumber yang dipengaruhi SQL dapat disimpan (urutan lebih tinggi), sebagai salah satu contoh, tetapi jelas parameter HTTP GET dan POST parameter dari bentuk HTML bukan satu-satunya cara pengguna memasukkan.

Kueri yang diparameterisasi tidak harus membuat pernyataan SQL Anda bebas dari suntikan. Mereka juga membutuhkan pengikatan variabel, penghapusan operasi string/penggabungan, dan menghindari masalah keamanan tertentu dengan sejumlah besar klausa SQL.

Sebagian besar pengembang juga lupa memeriksa komponen pihak ketiga dan dependensi lain untuk masalah injeksi SQL, dan terkadang tidak menyadari bahwa inklusi ini dapat membuat kode mereka sendiri rentan.

Hal terbaik untuk dilakukan adalah menyewa perusahaan konsultan keamanan aplikasi untuk menyiapkan aplikasi Anda untuk kesiapan produksi, dan untuk melatih tim appdev Anda dalam membangun kontrol keamanan aplikasi ke dalam proses dan teknologi pengembangan mereka.

4
atdre

Untuk memperluas jawaban Hendrick. Sangat mudah untuk menganggap real_escape_string sebagai peluru ajaib padahal kenyataannya tidak. Saya telah melihat orang menggunakan fungsi itu ketika mereka ingin menggunakan intval atau memasukkan input ke integer sebagai gantinya. Anda masih dapat disuntikkan jika menggunakan string pelolosan dalam konteks yang salah.

3
getahobby