Dalam hal injeksi SQL , saya sepenuhnya memahami perlunya parameterisasi string
parameter; itulah salah satu trik tertua dalam buku ini. Tapi kapan bisa dibenarkan untuk tidak membuat parameterisasi SqlCommand
? Apakah ada tipe data yang dianggap "aman" untuk tidak dijadikan parameter?
Sebagai contoh: Saya tidak menganggap diri saya berada di dekat seorang ahli dalam SQL, tetapi saya tidak dapat memikirkan kasus apa pun yang berpotensi rentan terhadap injeksi SQL untuk menerima bool
atau int
dan hanya menggabungkannya langsung ke kueri.
Apakah asumsi saya benar, atau dapatkah hal itu berpotensi meninggalkan kerentanan keamanan yang sangat besar dalam program saya?
Untuk klarifikasi, pertanyaan ini diberi tag c #yang merupakan bahasa yang diketik dengan kuat; ketika saya mengatakan "parameter", pikirkan sesuatu seperti public int Query(int id)
.
sumber
Jawaban:
Saya pikir itu aman ... secara teknis , tapi itu kebiasaan buruk untuk dilakukan. Apakah Anda benar-benar ingin menulis pertanyaan seperti ini?
Ini juga membuat Anda rentan dalam situasi di mana tipe berubah dari integer menjadi string (Pikirkan nomor karyawan yang, terlepas dari namanya - mungkin berisi huruf).
Jadi, kami telah mengubah jenis EmployeeNumber dari
int
menjadistring
, tetapi lupa memperbarui kueri sql kami. Ups.sumber
AddWithValue
? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/...AddWithValue
kecuali Anda memiliki pemetaan tipe database sebagai bagian dari bangunan dinamis pernyataan. Saya berasumsi bahwa Anda memiliki daftar kolom target, dan sebagai bagian dari kamus, Anda dapat memiliki tipe jika Anda mau. Jika tidak, terima saja kinerja yang dipukul. Pada akhirnya, menurut saya, hanya informasi yang baik untuk diketahui.AddWithValue
?" harus benar-benar "jika Anda tahu tipenya, maka Anda harus menahan diri untuk tidak menggunakanAddWithValue
.Bila menggunakan platform kuat-mengetik pada komputer Anda kontrol (seperti web server), Anda dapat mencegah kode injeksi untuk query dengan hanya
bool
,DateTime
atauint
(dan numerik lainnya) nilai-nilai. Yang menjadi perhatian adalah masalah kinerja yang disebabkan oleh memaksa server sql untuk mengkompilasi ulang setiap kueri, dan dengan mencegahnya mendapatkan statistik yang baik tentang kueri apa yang dijalankan dengan frekuensi apa (yang merugikan manajemen cache).Tetapi bagian "di komputer yang Anda kendalikan" itu penting, karena jika tidak, pengguna dapat mengubah perilaku yang digunakan oleh sistem untuk menghasilkan string dari nilai-nilai tersebut untuk menyertakan teks arbitrer.
Saya juga suka berpikir jangka panjang. Apa yang terjadi ketika basis kode yang diketik kuat yang lama dan rusak saat ini di-porting melalui terjemahan otomatis ke bahasa dinamis baru-panas, dan Anda tiba-tiba kehilangan pemeriksaan jenis, tetapi belum memiliki semua pengujian unit yang tepat untuk kode dinamis ?
Sungguh, tidak ada alasan bagus untuk tidak menggunakan parameter kueri untuk nilai-nilai ini. Ini cara yang benar untuk melakukan ini. Silakan dan nilai kode keras ke dalam string sql ketika mereka benar-benar konstanta, tetapi sebaliknya, mengapa tidak menggunakan parameter saja? Ini tidak sulit.
Pada akhirnya, saya tidak akan menyebut ini bug , tetapi saya akan menyebutnya bau : sesuatu yang tidak termasuk bug dengan sendirinya, tetapi merupakan indikasi kuat bahwa bug ada di sekitar, atau pada akhirnya akan ada. Kode yang baik menghindari meninggalkan bau, dan alat analisis statis yang baik akan menandai ini.
Saya akan menambahkan bahwa ini bukan, sayangnya, jenis argumen yang bisa Anda menangkan langsung. Kedengarannya seperti situasi di mana menjadi "benar" tidak lagi cukup, dan menginjak kaki rekan kerja Anda untuk memperbaiki masalah ini sendiri tidak akan mendorong dinamika tim yang baik; itu pada akhirnya bisa lebih menyakitkan daripada membantu. Pendekatan yang lebih baik dalam kasus ini mungkin mempromosikan penggunaan alat analisis statis. Itu akan memberikan legitimasi dan kredibilitas pada upaya yang ditujukan dan kembali serta memperbaiki kode yang ada.
sumber
DateTime
atauint
Dalam beberapa kasus, IS mungkin untuk melakukan serangan injeksi SQL dengan variabel non-parametrized (gabungan) selain nilai string - lihat artikel ini oleh Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -kultur / .
Masalahnya adalah ketika
ToString
dipanggil, beberapa penyedia budaya kustom dapat mengubah parameter non-string menjadi representasi stringnya yang memasukkan beberapa SQL ke dalam kueri.sumber
int
s?"CultureInfo
sulit untuk mengetahui mengapa Anda tetap membutuhkan SQL injection.Ini tidak aman bahkan untuk tipe non-string. Selalu gunakan parameter. Titik.
Pertimbangkan contoh kode berikut:
Sekilas kode terlihat aman, tetapi semuanya berubah jika Anda membuat beberapa perubahan di Pengaturan Regional Windows dan menambahkan injeksi dalam format tanggal pendek:
Sekarang teks perintah yang dihasilkan terlihat seperti ini:
Hal yang sama dapat dilakukan untuk
int
tipe karena pengguna dapat menentukan tanda negatif khusus yang dapat dengan mudah diubah menjadi injeksi SQL.Orang dapat berargumen bahwa budaya invarian harus digunakan sebagai pengganti budaya saat ini, tetapi saya telah melihat penggabungan string seperti ini berkali-kali dan cukup mudah untuk dilewatkan saat menggabungkan string dengan objek yang digunakan
+
.sumber
int
tipe tersebut?"SELECT * FROM Table1 WHERE Id =" + intVariable.ToString ()
Keamanan
Tidak apa-apa.
Penyerang tidak dapat menginjeksi apapun ke dalam variabel int yang Anda ketik.
Performa
Tidak OK.
Lebih baik menggunakan parameter, sehingga kueri akan dikompilasi sekali dan di-cache untuk penggunaan berikutnya. Lain kali bahkan dengan nilai parameter yang berbeda, kueri di-cache dan tidak perlu dikompilasi di server database.
Praktik Buruk Gaya Pengkodean .
"SELECT * FROM Product WHERE Id =" + TextBox1.Text
Meskipun ini bukan pertanyaan Anda, tapi mungkin berguna untuk pembaca selanjutnya:
Bencana Keamanan !
Meskipun
Id
kolomnya bilangan bulat, kueri Anda mungkin tunduk pada SQL Injection. Misalkan Anda memiliki kueri dalam aplikasi Anda"SELECT * FROM Table1 WHERE Id=" + TextBox1.Text
, Penyerang dapat memasukkan ke dalam kotak teks1; DELETE Table1
dan kueri tersebut akan menjadi:Jika Anda tidak ingin menggunakan kueri parametrized di sini, Anda harus menggunakan nilai yang diketik:
Pertanyaanmu
Saya pikir mengubah kode-kode itu tidak membuang-buang waktu. Memang perubahan itu Direkomendasikan!
jika rekan kerja Anda menggunakan variabel int, itu tidak memiliki risiko keamanan, Tapi menurut saya mengubah kode-kode itu tidak membuang-buang waktu dan memang disarankan untuk mengubah kode-kode itu. Itu membuat kode lebih mudah dibaca, lebih mudah dipelihara dan membuat eksekusi lebih cepat.
sumber
.ToString()
ditentukan oleh item konfigurasi sistem operasi yang mudah diubah untuk menyertakan teks arbitrer.Sebenarnya ada dua pertanyaan dalam satu. Dan pertanyaan dari judul tidak ada hubungannya dengan kekhawatiran yang diungkapkan oleh OP dalam komentar sesudahnya.
Meskipun saya menyadari bahwa untuk OP itu adalah kasus khusus mereka yang penting, bagi pembaca yang berasal dari Google, penting untuk menjawab pertanyaan yang lebih umum, yang dapat diutarakan sebagai "apakah penggabungan seaman pernyataan yang disiapkan jika saya memastikan bahwa setiap literal yang saya gabungkan aman? ". Jadi, saya ingin berkonsentrasi pada yang terakhir ini. Dan jawabannya adalah
Pasti TIDAK.
Penjelasannya tidak langsung seperti yang diinginkan kebanyakan pembaca, tetapi saya akan berusaha sebaik mungkin.
Saya telah merenungkan masalah ini untuk sementara waktu, menghasilkan artikel (meskipun berdasarkan lingkungan PHP) di mana saya mencoba merangkum semuanya. Terpikir oleh saya bahwa pertanyaan tentang perlindungan dari injeksi SQL sering kali luput dari beberapa topik terkait tetapi lebih sempit, seperti string escape, type casting, dan semacamnya. Meskipun beberapa tindakan dapat dianggap aman jika dilakukan sendiri, tidak ada sistem, atau aturan sederhana untuk diikuti. Yang membuatnya sangat licin, memberikan terlalu banyak perhatian dan pengalaman pengembang.
Pertanyaan tentang injeksi SQL tidak dapat disederhanakan menjadi masalah sintaks tertentu. Ini lebih luas dari yang biasa dipikirkan pengembang rata-rata. Ini juga pertanyaan metodologis . Ini tidak hanya "Pemformatan khusus mana yang harus kita terapkan", tetapi juga " Bagaimana hal itu harus dilakukan".
(Dari sudut pandang ini, sebuah artikel dari Jon Skeet yang dikutip dalam jawaban lain melakukan agak buruk daripada baik, karena lagi-lagi membahas beberapa kasus tepi, berkonsentrasi pada masalah sintaks tertentu dan gagal mengatasi masalah secara keseluruhan.)
Saat Anda mencoba menjawab pertanyaan tentang perlindungan tidak secara keseluruhan tetapi sebagai serangkaian masalah sintaksis yang berbeda, Anda menghadapi banyak masalah.
Tidak seperti kekacauan itu, pernyataan yang disiapkan memang The Holy Grail:
(Berpikir lebih jauh, saya menemukan bahwa set placeholder saat ini tidak cukup untuk kebutuhan kehidupan nyata dan harus diperluas, baik untuk struktur data yang kompleks, seperti array, dan bahkan kata kunci atau pengenal SQL, yang terkadang harus ditambahkan ke kueri secara dinamis juga, tetapi pengembang dibiarkan tidak bersenjata untuk kasus seperti itu, dan dipaksa untuk kembali ke penggabungan string tetapi itu masalah pertanyaan lain).
Menariknya, kontroversi pertanyaan ini dipicu oleh sifat Stack Overflow yang sangat kontroversial. Ide situs adalah memanfaatkan pertanyaan tertentu dari pengguna yang bertanya secara langsung untuk mencapai tujuan memiliki database jawaban tujuan umum yang sesuai untuk pengguna yang datang dari penelusuran . Idenya adalah tidak buruk per se , tetapi gagal dalam situasi seperti ini: ketika pengguna mengajukan pertanyaan yang sangat sempit , terutama untuk mendapatkan sebuah argumen dalam sengketa dengan rekan (atau untuk memutuskan apakah itu layak untuk refactor kode). Sementara sebagian besar peserta berpengalaman mencoba menulis jawaban, ingatlah misinya dari Stack Overflow secara keseluruhan, membuat jawaban mereka bagus untuk pembaca sebanyak mungkin, bukan hanya OP.
sumber
Mari kita tidak hanya memikirkan tentang keamanan atau pertimbangan keamanan tipe.
Alasan Anda menggunakan kueri parametrized adalah untuk meningkatkan kinerja di tingkat database. Dari perspektif database, kueri parametrized adalah satu kueri di buffer SQL (untuk menggunakan terminologi Oracle meskipun saya membayangkan semua database memiliki konsep yang serupa secara internal). Jadi, database dapat menampung sejumlah query dalam memori, disiapkan dan siap untuk dieksekusi. Kueri ini tidak perlu diurai dan akan lebih cepat. Query yang sering dijalankan biasanya ada di buffer dan tidak perlu diurai setiap kali digunakan.
KECUALI KALAU
Seseorang tidak menggunakan kueri parametrized. Dalam kasus ini, buffer terus-menerus dialirkan melalui aliran kueri yang hampir identik yang masing-masing perlu diurai dan dijalankan oleh mesin database dan kinerja menderita serba guna karena kueri yang sering dijalankan akhirnya diurai ulang berkali-kali a hari. Saya telah menyetel database untuk mencari nafkah dan ini telah menjadi salah satu sumber terbesar dari hasil yang menggantung rendah.
SEKARANG
Untuk menjawab pertanyaan Anda, JIKA kueri Anda memiliki sejumlah kecil nilai numerik yang berbeda, Anda mungkin tidak akan menyebabkan masalah dan bahkan dapat meningkatkan kinerja secara tak terbatas. JIKA ada potensi ratusan nilai dan kueri sering dipanggil, Anda akan memengaruhi kinerja sistem Anda, jadi jangan lakukan itu.
Ya, Anda dapat meningkatkan buffer SQL tetapi pada akhirnya selalu mengorbankan penggunaan lain yang lebih penting untuk memori seperti Caching Indeks atau Data. Moral, gunakan kueri parametrized dengan cukup religius sehingga Anda dapat mengoptimalkan database Anda dan menggunakan lebih banyak memori server untuk hal-hal yang penting ...
sumber
Untuk menambahkan beberapa info ke jawaban Maciek:
Sangat mudah untuk mengubah info budaya dari aplikasi pihak ketiga .NET dengan memanggil fungsi utama perakitan dengan refleksi:
Ini hanya berfungsi jika fungsi Utama BobbysApp bersifat publik. Jika Utama tidak umum, mungkin ada fungsi publik lain yang dapat Anda hubungi.
sumber
Menurut pendapat saya, jika Anda dapat menjamin bahwa parameter yang Anda kerjakan tidak akan pernah berisi string, itu aman tetapi saya tidak akan melakukannya dalam hal apa pun. Selain itu, Anda akan melihat sedikit penurunan kinerja karena Anda melakukan penggabungan. Pertanyaan yang ingin saya tanyakan adalah mengapa Anda tidak ingin menggunakan parameter?
sumber
Tidak apa-apa tetapi tidak pernah aman .. dan keamanan selalu bergantung pada input, misalnya jika objek input adalah TextBox, penyerang dapat melakukan sesuatu yang rumit karena kotak teks dapat menerima string, jadi Anda harus meletakkan semacam validasi / konversi untuk dapat mencegah pengguna salah memasukkan. Tapi masalahnya, itu tidak aman. Sesederhana itu.
sumber
Tidak, Anda bisa mendapatkan serangan injeksi SQL dengan cara itu. Saya telah menulis artikel lama dalam bahasa Turki yang menunjukkan caranya di sini . Contoh artikel di PHP dan MySQL tetapi konsep berfungsi sama di C # dan SQL Server.
Pada dasarnya Anda menyerang dengan cara berikut. Mari pertimbangkan Anda memiliki halaman yang menampilkan informasi sesuai dengan nilai id integer. Anda tidak mengukur nilai ini, seperti di bawah ini.
Oke, saya asumsikan Anda menggunakan MySQL dan saya menyerang dengan cara berikut.
Perhatikan bahwa nilai yang dimasukkan di sini bukanlah string. Kami mengubah nilai karakter menjadi int menggunakan fungsi ASCII. Anda dapat mencapai hal yang sama di SQL Server menggunakan "CAST (YourVarcharCol AS INT)".
Setelah itu saya menggunakan fungsi panjang dan substring untuk mengetahui nama database Anda.
Kemudian dengan menggunakan nama database, Anda mulai mendapatkan nama tabel di database.
Tentu saja Anda harus mengotomatiskan proses ini, karena Anda hanya mendapatkan SATU karakter per kueri. Tetapi Anda dapat dengan mudah mengotomatiskannya. Artikel saya menunjukkan satu contoh di watir . Hanya menggunakan satu halaman dan bukan nilai ID berparameter. Saya bisa mempelajari setiap nama tabel di database Anda. Setelah itu saya bisa mencari tabel penting. Ini akan memakan waktu tetapi itu bisa dilakukan.
sumber
public void QuerySomething(int id) { // this will only accept an integer }
Nah ... satu hal yang pasti: Keamanan TIDAK ok, ketika Anda menggabungkan string (diambil oleh pengguna) dengan string perintah SQL Anda. Tidak masalah kapan pun klausa where mengacu pada Integer atau tipe apa pun; suntikan bisa terjadi.
Yang penting dalam SQL Injection adalah tipe data dari variabel yang digunakan untuk mendapatkan nilai dari pengguna.
Misalkan kita memiliki integer di klausa where dan:
variabel pengguna adalah string. Maka ok, tidak mudah untuk menginjeksi (menggunakan UNION) tetapi sangat mudah untuk melewati menggunakan 'OR 1 = 1' - seperti serangan ...
Jika variabel pengguna adalah bilangan bulat. Kemudian lagi kita dapat 'menguji' kekuatan sistem dengan melewati pengujian angka besar yang tidak biasa untuk sistem crash atau bahkan untuk buffer overflow tersembunyi (pada string terakhir) ...;)
Mungkin parameter untuk kueri atau (bahkan lebih baik - imo) ke Prosedur Tersimpan bukanlah 100% Ancaman yang aman, tetapi mereka adalah ukuran yang paling tidak diperlukan (atau yang paling dasar jika Anda lebih suka) untuk meminimalkannya.
sumber