Saya menyadari bahwa kueri SQL berparameter adalah cara optimal untuk membersihkan masukan pengguna saat membuat kueri yang berisi masukan pengguna, tetapi saya bertanya-tanya apa yang salah dengan mengambil masukan pengguna dan melepaskan tanda kutip tunggal dan mengelilingi seluruh string dengan tanda kutip tunggal. Berikut kodenya:
sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"
Kutipan tunggal apa pun yang dimasukkan pengguna diganti dengan tanda kutip tunggal ganda, yang menghilangkan kemampuan pengguna untuk mengakhiri string, jadi apa pun yang mereka ketik, seperti titik koma, tanda persen, dll., Semuanya akan menjadi bagian dari string dan tidak benar-benar dijalankan sebagai bagian dari perintah.
Kami menggunakan Microsoft SQL Server 2000, yang menurut saya kutipan tunggal adalah satu-satunya pemisah string dan satu-satunya cara untuk keluar dari pemisah string, jadi tidak ada cara untuk mengeksekusi apa pun yang diketik pengguna.
Saya tidak melihat cara untuk meluncurkan serangan injeksi SQL terhadap ini, tetapi saya menyadari bahwa jika ini antipeluru seperti yang terlihat bagi saya, orang lain akan memikirkannya dan itu akan menjadi praktik umum.
Ada apa dengan kode ini? Apakah ada cara untuk mendapatkan serangan injeksi SQL melewati teknik sanitasi ini? Contoh masukan pengguna yang memanfaatkan teknik ini akan sangat membantu.
MEMPERBARUI:
Saya masih tidak tahu cara apa pun untuk meluncurkan serangan injeksi SQL secara efektif terhadap kode ini. Beberapa orang menyarankan bahwa garis miring terbalik akan keluar dari satu kutipan tunggal dan membiarkan yang lain mengakhiri string sehingga sisa string akan dieksekusi sebagai bagian dari perintah SQL, dan saya menyadari bahwa metode ini akan berfungsi untuk menyuntikkan SQL ke dalam database MySQL, tetapi di SQL Server 2000 satu-satunya cara (yang dapat saya temukan) untuk keluar dari kutipan tunggal adalah dengan kutipan tunggal lainnya; garis miring terbalik tidak akan berhasil.
Dan kecuali jika ada cara untuk menghentikan pelolosan kutipan tunggal, tidak ada input pengguna lainnya yang akan dieksekusi karena semuanya akan diambil sebagai satu string yang berdekatan.
Saya memahami bahwa ada cara yang lebih baik untuk membersihkan masukan, tetapi saya benar-benar lebih tertarik untuk mempelajari mengapa metode yang saya berikan di atas tidak berfungsi. Jika ada yang tahu cara khusus untuk memasang serangan injeksi SQL terhadap metode sanitasi ini, saya akan senang melihatnya.
Jawaban:
Pertama-tama, ini hanya praktik yang buruk. Validasi input selalu diperlukan, tetapi juga selalu rapuh.
Lebih buruk lagi, validasi daftar hitam selalu bermasalah, jauh lebih baik untuk secara eksplisit dan ketat menentukan nilai / format apa yang Anda terima. Memang, ini tidak selalu memungkinkan - tetapi sampai batas tertentu hal itu harus selalu dilakukan.
Beberapa makalah penelitian tentang subjek:
Intinya adalah, daftar hitam apa pun yang Anda lakukan (dan daftar putih yang terlalu permisif) dapat dilewati. Tautan terakhir ke makalah saya menunjukkan situasi di mana bahkan pelepasan kutipan dapat dilewati.
Meskipun situasi ini tidak berlaku untuk Anda, itu tetap merupakan ide yang buruk. Selain itu, kecuali aplikasi Anda kecil sekali, Anda harus berurusan dengan pemeliharaan, dan mungkin sejumlah tata kelola: bagaimana Anda memastikan bahwa aplikasi tersebut dilakukan dengan benar, di mana saja sepanjang waktu?
Cara yang tepat untuk melakukannya:
sumber
sp_executesql
alih - alihEXEC
). Artinya, Anda dapat membuat pernyataan SQL secara dinamis selama tidak ada teks gabungan yang berasal dari pengguna. Ini juga memiliki manfaat kinerja;sp_executesql
mendukung caching.Oke, tanggapan ini akan terkait dengan pembaruan pertanyaan:
Sekarang, selain MySQL backslash escaping - dan dengan mempertimbangkan bahwa kita sebenarnya berbicara tentang MSSQL, sebenarnya ada 3 cara yang mungkin untuk tetap memasukkan SQL ke kode Anda.
Perhatikan bahwa ini tidak semua valid setiap saat, dan sangat bergantung pada kode aktual Anda di sekitarnya:
Maka yang Anda dapatkan - adalah nama pengguna, lolos, dan kemudian dipangkas menjadi 20 karakter. Masalahnya di sini - Saya akan menempelkan kutipan saya di karakter ke-20 (misalnya setelah 19 a), dan kutipan lolos Anda akan dipangkas (di karakter ke-21). Kemudian SQL
sSQL = "select * from USERS where username = '" + username + "' and password = '" + password + "'"
dikombinasikan dengan nama pengguna yang salah format tersebut akan menghasilkan kata sandi yang sudah berada di luar tanda kutip, dan hanya akan berisi muatan secara langsung.
3. Penyelundupan Unicode - Dalam situasi tertentu, dimungkinkan untuk mengirimkan karakter unicode tingkat tinggi yang terlihat seperti kutipan, tetapi sebenarnya bukan - sampai ia masuk ke database, di mana tiba - tiba ia berada . Karena ini bukan kutipan saat Anda memvalidasinya, itu akan mudah ... Lihat tanggapan saya sebelumnya untuk lebih jelasnya, dan tautkan ke penelitian asli.
sumber
Singkatnya: Jangan pernah melakukan kueri yang keluar dari diri Anda sendiri. Anda pasti akan mendapatkan sesuatu yang salah. Sebagai gantinya, gunakan kueri berparameter, atau jika Anda tidak bisa melakukannya karena alasan tertentu, gunakan pustaka yang sudah ada yang melakukan ini untuk Anda. Tidak ada alasan untuk melakukannya sendiri.
sumber
Saya menyadari ini sudah lama setelah pertanyaan diajukan, tapi ..
Salah satu cara untuk meluncurkan serangan pada prosedur 'kutipan argumen' adalah dengan pemotongan string. Menurut MSDN, di SQL Server 2000 SP4 (dan SQL Server 2005 SP1), string yang terlalu panjang akan dipotong secara diam-diam.
Saat Anda mengutip string, ukuran string bertambah. Setiap tanda kutip diulangi. Ini kemudian dapat digunakan untuk mendorong bagian-bagian SQL di luar buffer. Jadi Anda dapat secara efektif memangkas bagian klausa di mana.
Ini mungkin akan sangat berguna dalam skenario halaman 'admin pengguna' di mana Anda dapat menyalahgunakan pernyataan 'update' untuk tidak melakukan semua pemeriksaan yang seharusnya dilakukan.
Jadi jika Anda memutuskan untuk mengutip semua argumen, pastikan Anda tahu apa yang terjadi dengan ukuran string dan memastikan bahwa Anda tidak mengalami pemotongan.
Saya akan merekomendasikan menggunakan parameter. Selalu. Hanya berharap saya bisa menerapkannya di database. Dan sebagai efek sampingnya, Anda lebih cenderung mendapatkan klik cache yang lebih baik karena lebih banyak pernyataan yang terlihat sama. (Ini memang benar di Oracle 8)
sumber
Saya telah menggunakan teknik ini ketika berurusan dengan fungsionalitas 'pencarian lanjutan', di mana membuat kueri dari awal adalah satu-satunya jawaban yang layak. (Contoh: izinkan pengguna untuk mencari produk berdasarkan sekumpulan batasan tak terbatas pada atribut produk, menampilkan kolom dan nilai yang diizinkan sebagai kontrol GUI untuk mengurangi ambang pembelajaran bagi pengguna.)
Dengan sendirinya AFAIK aman. Seperti yang ditunjukkan oleh penjawab lain, Anda mungkin juga perlu berurusan dengan pelolosan backspace (meskipun tidak saat meneruskan kueri ke SQL Server menggunakan ADO atau ADO.NET, setidaknya - tidak dapat menjamin semua database atau teknologi).
Halangannya adalah Anda benar-benar harus memastikan string mana yang berisi input pengguna (selalu berpotensi berbahaya), dan string mana yang merupakan kueri SQL yang valid. Salah satu jebakannya adalah jika Anda menggunakan nilai dari database - apakah nilai tersebut awalnya disediakan oleh pengguna? Jika demikian, mereka juga harus melarikan diri. Jawaban saya adalah mencoba membersihkan selambat mungkin (tetapi tidak nanti!), Saat membuat kueri SQL.
Namun, dalam banyak kasus, pengikatan parameter adalah cara yang harus dilakukan - hanya saja lebih sederhana.
sumber
Sanitasi input bukanlah sesuatu yang ingin Anda setengah-setengah. Gunakan seluruh pantatmu. Gunakan ekspresi reguler pada bidang teks. TryCast numerik Anda ke jenis numerik yang tepat, dan laporkan kesalahan validasi jika tidak berhasil. Sangat mudah untuk mencari pola serangan di masukan Anda, seperti '-. Asumsikan semua masukan dari pengguna tidak bersahabat.
sumber
flavors
di halaman itu).Bagaimanapun, itu ide yang buruk seperti yang Anda ketahui.
Bagaimana dengan sesuatu seperti keluar dari kutipan dalam string seperti ini: \ '
Penggantian Anda akan menghasilkan: \ ''
Jika garis miring terbalik keluar dari kutipan pertama, maka kutipan kedua telah mengakhiri string.
sumber
Jawaban sederhana: Ini kadang-kadang akan berhasil, tetapi tidak setiap saat. Anda ingin menggunakan validasi daftar putih pada semua yang Anda lakukan, tetapi saya menyadari itu tidak selalu memungkinkan, jadi Anda terpaksa menggunakan daftar hitam tebakan terbaik. Demikian juga, Anda ingin menggunakan procs tersimpan parametrized dalam segala hal , tetapi sekali lagi, itu tidak selalu memungkinkan, jadi Anda terpaksa menggunakan sp_execute dengan parameter.
Ada beberapa cara di sekitar daftar hitam yang dapat digunakan yang dapat Anda buat (dan beberapa daftar putih juga).
Tulisan yang layak ada di sini: http://www.owasp.org/index.php/Top_10_2007-A2
Jika Anda perlu melakukan ini sebagai perbaikan cepat untuk memberi Anda waktu untuk mendapatkan yang asli, lakukanlah. Tapi jangan berpikir Anda aman.
sumber
Ada dua cara untuk melakukannya, tanpa pengecualian, agar aman dari injeksi SQL; pernyataan yang disiapkan atau prosedur tersimpan prameterized.
sumber
Jika Anda memiliki kueri berparameter yang tersedia, Anda harus menggunakannya setiap saat. Yang diperlukan hanyalah satu kueri untuk lolos dari internet dan DB Anda berisiko.
sumber
Ya, itu akan berhasil sampai seseorang menjalankan SET QUOTED_IDENTIFIER OFF dan menggunakan tanda kutip ganda pada Anda.
Sunting: Ini tidak sesederhana tidak mengizinkan pengguna jahat untuk mematikan pengenal yang dikutip:
Ada banyak cara QUOTED_IDENTIFIER bisa mati tanpa Anda sadari. Memang - ini bukan eksploitasi senjata api yang Anda cari, tetapi ini permukaan serangan yang cukup besar. Tentu saja, jika Anda juga lolos dari tanda kutip ganda - maka kita kembali ke awal. ;)
sumber
Pertahanan Anda akan gagal jika:
(dalam kasus terakhir, itu harus menjadi sesuatu yang diperluas hanya setelah Anda selesai mengganti)
sumber
Patrick, apakah Anda menambahkan tanda kutip tunggal di sekitar SEMUA masukan, bahkan masukan numerik? Jika Anda memiliki input numerik, tetapi tidak menempatkan tanda kutip tunggal di sekitarnya, maka Anda memiliki eksposur.
sumber
Betapa jeleknya kode semua sanitasi input pengguna itu! Kemudian StringBuilder yang kikuk untuk pernyataan SQL. Metode pernyataan yang disiapkan menghasilkan kode yang jauh lebih bersih, dan manfaat SQL Injection adalah tambahan yang sangat bagus.
Juga mengapa menemukan kembali roda?
sumber
Daripada mengubah satu kutipan menjadi (seperti apa) dua kutipan tunggal, mengapa tidak mengubahnya menjadi apostrof, kutipan, atau menghapus seluruhnya?
Either way, itu sedikit kludge ... terutama ketika Anda secara sah memiliki hal-hal (seperti nama) yang mungkin menggunakan tanda kutip tunggal ...
CATATAN: Metode Anda juga mengasumsikan setiap orang yang mengerjakan aplikasi Anda selalu ingat untuk membersihkan input sebelum masuk ke database, yang mungkin tidak realistis hampir sepanjang waktu.
sumber
Meskipun Anda mungkin menemukan solusi yang berfungsi untuk string, untuk predikat numerik Anda juga perlu memastikan bahwa mereka hanya meneruskan angka (periksa sederhana apakah dapat diuraikan sebagai int / double / desimal?).
Ini banyak pekerjaan ekstra.
sumber
Mungkin berhasil, tetapi bagi saya tampaknya sedikit tipu. Saya akan merekomendasikan untuk memverifikasi bahwa setiap string valid dengan mengujinya terhadap ekspresi reguler.
sumber
Ya, Anda bisa, jika ...
Setelah mempelajari topik tersebut, menurut saya masukan yang disterilkan seperti yang Anda sarankan aman, tetapi hanya berdasarkan aturan berikut:
Anda tidak pernah mengizinkan nilai string yang berasal dari pengguna menjadi apa pun selain literal string (yaitu, hindari memberikan opsi konfigurasi: "Masukkan nama / ekspresi kolom SQL tambahan di sini:"). Tipe nilai selain string (angka, tanggal, ...): konversikan ke tipe data aslinya dan sediakan rutin untuk literal SQL dari setiap tipe data.
Anda bisa menggunakan
nvarchar
/nchar
kolom (dan awalan string literal denganN
) ATAU membatasi nilai masuk kevarchar
/char
kolom hanya untuk karakter ASCII (misalnya, membuang pengecualian saat membuat pernyataan SQL)Anda selalu memvalidasi panjang nilai agar sesuai dengan panjang kolom sebenarnya (buang pengecualian jika lebih panjang)
Anda memastikan itu
SET QUOTED_IDENTIFIER
selaluON
Mematuhi 4 poin ini, Anda harus aman. Jika Anda melanggar salah satunya, cara injeksi SQL terbuka.
sumber