Saya membuat prosedur tersimpan berikut ini:
ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender
Sekarang, saya mencoba melakukan sesuatu seperti ini. Mungkin saya melakukan ini salah, tapi saya ingin memastikan bahwa prosedur seperti itu dapat mencegah SQL Injection:
EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'
Gambar di bawah ini menunjukkan SQL di atas dieksekusi dalam SSMS dan hasilnya ditampilkan dengan benar alih-alih kesalahan:
Btw, saya menambahkan bagian yang mengikuti tanda titik koma setelah permintaan selesai dieksekusi. Kemudian saya menjalankannya lagi, tetapi ketika saya memeriksa untuk melihat apakah tabel tblActor ada atau tidak, itu masih ada. Apakah saya melakukan sesuatu yang salah? Atau apakah ini benar-benar anti-injeksi? Saya kira apa yang saya coba tanyakan di sini juga adalah apakah prosedur tersimpan seperti ini aman? Terima kasih.
EXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'
Jawaban:
Kode ini berfungsi dengan baik karena:
Agar SQL Injection berfungsi, Anda harus membuat string kueri (yang tidak Anda lakukan) dan tidak menerjemahkan apostrof tunggal (
'
) ke dalam escaped-apostrophes (''
) (yang diloloskan melalui parameter input).Dalam upaya Anda untuk memberikan nilai "kompromi",
'Male; DROP TABLE tblActor'
string itu hanya itu, string biasa.Sekarang, jika Anda melakukan sesuatu seperti:
maka yang akan rentan terhadap SQL Injection karena itu permintaan tidak di saat ini, konteks pra-parsing; permintaan itu hanyalah string lain saat ini. Jadi nilai
@InputParam
bisa'2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
dan yang mungkin menimbulkan masalah karena permintaan itu akan diberikan, dan dieksekusi, seperti:Ini adalah salah satu (dari beberapa) alasan utama untuk menggunakan Prosedur Tersimpan: secara inheren lebih aman (well, selama Anda tidak menghindari keamanan itu dengan membangun kueri seperti yang saya perlihatkan di atas tanpa memvalidasi nilai dari parameter apa pun yang digunakan). Meskipun jika Anda perlu membangun SQL Dinamis, cara yang lebih disukai adalah membuat parameter itu juga menggunakan
sp_executesql
:Dengan menggunakan pendekatan ini, seseorang yang mencoba
'2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
untukDATETIME
memasukkan parameter input akan mendapatkan kesalahan saat menjalankan Prosedur Tersimpan. Atau bahkan jika Prosedur Tersimpan diterima@InputParameter
sebagaiNVARCHAR(100)
, itu harus dikonversi keDATETIME
dalam untuk masuk kesp_executesql
panggilan itu. Dan bahkan jika parameter dalam SQL Dinamis adalah tipe string, masuk ke Prosedur Tersimpan di tempat pertama setiap tanda kutip otomatis akan lolos ke tanda kutip ganda.Ada jenis serangan yang kurang dikenal di mana penyerang mencoba untuk mengisi bidang input dengan tanda kutip sedemikian sehingga string di dalam Prosedur Tersimpan yang akan digunakan untuk membangun SQL Dinamis tetapi yang dinyatakan terlalu kecil tidak dapat memuat semuanya dan mendorong tanda kutip akhir dan entah bagaimana berakhir dengan jumlah tanda kutip yang benar sehingga tidak lagi "melarikan diri" dalam string. Ini disebut Pemotongan SQL dan dibicarakan dalam artikel majalah MSDN berjudul "Serangan Pemotongan SQL Baru dan Cara Menghindarinya", oleh Bala Neerumalla, tetapi artikel itu tidak lagi online. Masalah yang mengandung artikel ini - edisi November, 2006 MSDN Magazine - hanya tersedia sebagai file Bantuan Windows (dalam .chmformat). Jika Anda mengunduhnya, itu mungkin tidak terbuka karena pengaturan keamanan default. Jika ini terjadi, klik kanan pada file MSDNMagazineNovember2006en-us.chm dan pilih "Properties". Di salah satu tab itu akan ada opsi untuk "Percayai jenis file ini" (atau sesuatu seperti itu) yang perlu diperiksa / diaktifkan. Klik tombol "OK" dan kemudian coba buka kembali file .chm .
Variasi lain dari serangan Truncation adalah, dengan asumsi variabel lokal digunakan untuk menyimpan nilai "aman" yang disediakan pengguna karena setiap tanda kutip ganda digandakan sehingga dapat diloloskan, untuk mengisi variabel lokal itu dan menempatkan tanda kutip tunggal pada akhirnya. Idenya di sini adalah bahwa jika variabel lokal tidak berukuran benar, tidak akan ada cukup ruang di akhir untuk penawaran tunggal kedua, biarkan variabel diakhiri dengan penawaran tunggal tunggal yang kemudian digabungkan dengan penawaran tunggal yang mengakhiri nilai literal dalam SQL Dinamis, mengubah kutip tunggal yang berakhir menjadi kutipan tunggal yang diloloskan, dan string literal dalam Dynamic SQL kemudian diakhiri dengan kutipan-tunggal berikutnya yang dimaksudkan untuk memulai string literal berikutnya. Sebagai contoh:
Di sini, Dynamic SQL yang akan dieksekusi sekarang:
Dynamic SQL yang sama, dalam format yang lebih mudah dibaca, adalah:
Memperbaiki ini mudah. Lakukan saja salah satu dari yang berikut:
Jangan gunakan variabel lokal untuk menyimpan nilai "tetap"; cukup masukkan
REPLACE()
langsung ke dalam penciptaan Dynamic SQL:Dynamic SQL tidak lagi dikompromikan:
Catatan tentang contoh Trunction di atas:
DELETE tableName
menjadi destruktif, tetapi kecil kemungkinannya untuk menambahkan pengguna pintu belakang, atau mengubah kata sandi admin.Untuk informasi lebih rinci terkait dengan SQL Injection (mencakup berbagai RDBMS dan skenario), silakan lihat yang berikut dari Proyek Keamanan Aplikasi Web Terbuka (OWASP):
Pengujian untuk SQL Injection
Terkait Stack Overflow jawaban pada SQL Injection dan SQL Truncation:
Seberapa amankah T-SQL setelah Anda mengganti karakter 'escape?
sumber
Masalah sederhananya adalah Anda sama sekali tidak membingungkan data dengan perintah. Nilai untuk parameter tidak pernah diperlakukan sebagai bagian dari perintah, dan karenanya tidak pernah dieksekusi.
Saya membuat blog tentang ini di: http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/
sumber