Rabu, 12 Oktober 2011

SqL injection

SQL Injection
SQL Server 2008 R2
Versi lainnya




SQL injection adalah sebuah serangan di mana kode berbahaya dimasukkan ke dalam string yang kemudian diteruskan ke sebuah instance dari SQL Server untuk parsing dan eksekusi. Setiap prosedur yang konstruksi pernyataan SQL harus ditinjau untuk kerentanan injeksi karena SQL Server akan mengeksekusi semua pertanyaan sintaktis yang valid yang diterimanya. Parameter data bahkan dapat dimanipulasi oleh penyerang terampil dan ditentukan.

Bentuk injeksi SQL utama terdiri dari penyisipan langsung kode ke user-input variabel yang bersambung dengan perintah SQL dan dieksekusi. Serangan tidak langsung menyuntikkan kode berbahaya ke dalam string yang ditakdirkan untuk penyimpanan dalam sebuah tabel atau sebagai metadata. Ketika string disimpan selanjutnya concatenated ke perintah SQL dinamis, kode berbahaya dijalankan.

Proses injeksi bekerja dengan prematur mengakhiri string teks dan menambahkan perintah baru. Karena perintah dimasukkan mungkin telah ditambahkan string tambahan untuk itu sebelum dieksekusi, penjahat berakhir string disuntikkan dengan tanda komentar "--". Teks berikutnya diabaikan pada waktu eksekusi.

Naskah berikut menunjukkan injeksi SQL sederhana. Script membangun sebuah query SQL oleh concatenating string keras-kode bersama-sama dengan string yang dimasukkan oleh pengguna:
lainnya
var Shipcity;
ShipCity = Request.Form ("ShipCity");
var sql = "select * from OrdersTable mana ShipCity = '" + ShipCity + "'";

Pengguna diminta untuk memasukkan nama kota. Jika dia masuk Redmond, query dirakit oleh script terlihat mirip dengan berikut:

SELECT * FROM OrdersTable MANA ShipCity = 'Redmond'

Namun, mengasumsikan bahwa pengguna memasukan berikut:

Redmond '; drop-OrdersTable meja -

Dalam hal ini, query berikut ini dirakit oleh script:

SELECT * FROM OrdersTable MANA ShipCity = 'Redmond'; drop tabel OrdersTable - '

Titik koma (;) menunjukkan akhir satu permintaan dan awal lagi. Tanda hubung ganda (-) menunjukkan bahwa sisa baris saat ini adalah sebuah komentar dan harus diabaikan. Jika kode diubah secara sintaktis adalah benar, maka akan dieksekusi oleh server. Ketika proses SQL Server pernyataan ini, SQL Server pertama akan memilih semua catatan dalam OrdersTable mana ShipCity adalah Redmond. Kemudian, SQL Server akan turun OrdersTable.

Selama kode SQL disuntikkan secara sintaktis adalah benar, gangguan tidak dapat dideteksi pemrograman. Oleh karena itu, Anda harus memvalidasi semua input pengguna dan hati-hati kode review yang mengeksekusi perintah SQL dibangun pada server yang Anda gunakan. Praktik terbaik coding dijelaskan di bagian berikut dalam topik ini.
Validasi input Semua

Selalu memvalidasi input pengguna dengan jenis pengujian, panjang, format, dan jangkauan. Ketika Anda menerapkan tindakan pencegahan terhadap input berbahaya, mempertimbangkan skenario arsitektur dan penyebaran aplikasi Anda. Ingat bahwa program yang dirancang untuk berjalan di lingkungan yang aman dapat disalin ke lingkungan tidak aman. Saran-saran berikut harus dipertimbangkan praktek terbaik:

Tidak membuat asumsi tentang jenis, ukuran, atau isi dari data yang diterima oleh aplikasi Anda. Misalnya, Anda harus membuat evaluasi berikut:

Bagaimana aplikasi Anda bersikap jika pengguna bersalah atau berbahaya memasuki MPEG 10-megabyte di mana aplikasi Anda mengharapkan kode pos?

Bagaimana aplikasi Anda bersikap jika pernyataan DROP TABLE tertanam dalam kolom teks?

Uji ukuran dan tipe data input dan menegakkan batas-batas yang tepat. Hal ini dapat membantu mencegah buffer overruns disengaja.

Uji isi variabel string dan hanya menerima nilai-nilai yang diharapkan. Tolak entri yang berisi data biner, urutan melarikan diri, dan karakter komentar. Hal ini dapat membantu mencegah injeksi script dan dapat melindungi terhadap beberapa eksploitasi buffer overrun.

Ketika Anda bekerja dengan dokumen XML, memvalidasi semua data terhadap skema-nya seperti yang dimasukkan.

Pernah membangun Transact-SQL langsung dari input pengguna.

Gunakan prosedur yang tersimpan untuk memvalidasi input pengguna.

Dalam lingkungan multitier, semua data harus divalidasi sebelum masuk ke zona dipercaya. Data yang tidak lulus proses validasi harus ditolak dan kesalahan harus dikembalikan ke tingkat sebelumnya.

Melaksanakan beberapa lapisan validasi. Anda mengambil tindakan pencegahan terhadap pengguna santai berbahaya mungkin tidak efektif terhadap penyerang ditentukan. Praktek yang lebih baik adalah untuk memvalidasi input pada antarmuka pengguna dan di semua titik berikutnya di mana ia melintasi batas kepercayaan.

Sebagai contoh, data validasi dalam aplikasi sisi klien dapat mencegah injeksi script sederhana. Namun, jika tingkat berikutnya mengasumsikan bahwa input telah divalidasi, setiap pengguna berbahaya yang dapat memotong klien dapat memiliki akses tidak terbatas terhadap sistem.

Jangan pernah menggabungkan input pengguna yang tidak divalidasi. Rangkaian String adalah titik utama masuk untuk injeksi script.

Jangan menerima string berikut di bidang dari mana nama file dapat dibangun: AUX, CLOCK $, COM1 melalui COM8, CON, CONFIG $, LPT1 melalui LPT8, Nul, dan PRN.

Ketika Anda bisa, menolak masukan yang berisi karakter berikut.
Input karakter
Makna dalam Transact-SQL

;
Pertanyaan pembatas.

'
Karakter data string delimiter.

-
Komentar pembatas.

/ * ... * /
Komentar pembatas. Teks antara / * dan * / tidak dievaluasi oleh server.

xp_
Digunakan pada awal nama katalog-diperpanjang prosedur yang tersimpan, seperti xp_cmdshell.

Jenis-Aman Gunakan Parameter SQL

Koleksi Parameter di SQL Server menyediakan memeriksa jenis dan validasi panjang. Jika Anda menggunakan koleksi Parameter, masukan diperlakukan sebagai nilai literal bukan sebagai kode dieksekusi. Sebuah keuntungan tambahan dari menggunakan koleksi Parameter adalah bahwa Anda dapat menegakkan cek jenis dan panjang. Nilai di luar jangkauan akan memicu pengecualian. Fragmen kode berikut menunjukkan menggunakan koleksi Parameter:
lainnya
SqlDataAdapter myCommand = new SqlDataAdapter ("AuthorLogin", conn);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add ("@ au_id",
SqlDbType.VarChar, 11);
parm.Value = Login.Text;

Dalam contoh ini, parameter @ au_id diperlakukan sebagai nilai literal bukan sebagai kode dieksekusi. Nilai ini dicek tipe dan panjangnya. Jika nilai @ au_id tidak sesuai dengan jenis tertentu dan kendala panjang, pengecualian akan dilempar.
Gunakan Masukan parameterized dengan Stored Procedures

Prosedur yang tersimpan mungkin rentan terhadap SQL injection jika mereka menggunakan tanpa filter masukan. Sebagai contoh, kode berikut ini rentan:
lainnya
SqlDataAdapter myCommand =
baru SqlDataAdapter ("LoginStoredProcedure '" +
Login.Text + "'", conn);

Jika Anda menggunakan prosedur yang tersimpan, Anda harus menggunakan parameter sebagai masukan mereka.
Gunakan Koleksi Parameter dengan Dynamic SQL

Jika Anda tidak dapat menggunakan prosedur yang tersimpan, Anda masih bisa menggunakan parameter, seperti yang ditunjukkan dalam contoh kode berikut:
lainnya
SqlDataAdapter myCommand = SqlDataAdapter baru (
"SELECT au_lname, au_fname DARI MANA Penulis au_id = @ au_id", conn);
SqlParameter parm = myCommand.SelectCommand.Parameters.Add ("@ au_id",
SqlDbType.VarChar, 11);
Parm.Value = Login.Text;
Masukan Penyaringan

Penyaringan masukan juga dapat membantu dalam melindungi terhadap injeksi SQL dengan menghapus karakter melarikan diri. Namun, karena banyaknya karakter yang dapat menimbulkan masalah, ini bukan pertahanan dapat diandalkan. Contoh berikut pencarian untuk string karakter pembatas.
lainnya
swasta String SafeSqlLiteral (string inputSQL)
{
kembali inputSQL.Replace ("'", "''");
}
SEPERTI Klausul

Catatan bahwa jika Anda menggunakan klausa SEPERTI, karakter wildcard masih harus melarikan diri:
lainnya
s = s.Replace ("[", "[[]");
s = s.Replace ("%", "[%]");
s = s.Replace ("_", "[_]");
Meninjau Kode untuk SQL Injection

Anda harus meninjau semua kode yang memanggil EXECUTE, EXEC, atau sp_executesql. Anda dapat menggunakan query mirip dengan yang berikut untuk membantu Anda mengidentifikasi prosedur yang berisi pernyataan-pernyataan. Cek query ini selama 1, 2, 3, atau 4 spasi setelah kata-kata Execute atau EXEC.

SELECT object_name (id) DARI syscomments

MANA UPPER (teks) LIKE '% EXECUTE (%'

ATAU UPPER (teks) LIKE '% EXECUTE (%'

ATAU UPPER (teks) LIKE '% EXECUTE (%'

ATAU UPPER (teks) LIKE '% EXECUTE (%'

ATAU UPPER (teks) LIKE '% EXEC (%'

ATAU UPPER (teks) LIKE '% EXEC (%'

ATAU UPPER (teks) LIKE '% EXEC (%'

ATAU UPPER (teks) LIKE '% EXEC (%'

ATAU UPPER (teks) LIKE '% sp_executesql%'
Parameter pembungkus dengan QUOTENAME () dan REPLACE ()

Dalam setiap prosedur yang tersimpan yang dipilih, pastikan bahwa semua variabel yang digunakan dalam Transact-SQL dinamis ditangani dengan benar. Data yang berasal dari parameter masukan dari prosedur yang disimpan atau dibaca dari tabel harus dibungkus QUOTENAME () atau REPLACE (). Ingat bahwa nilai variabel @ yang dilewatkan ke QUOTENAME () adalah sysname, dan memiliki panjang maksimum 128 karakter.
@ Variabel
Rekomendasi wrapper

Nama securable
QUOTENAME (@ variabel)

String ≤ 128 karakter
QUOTENAME (@ variabel,'''')

String> 128 karakter
REPLACE (@ variabel ,'''','''''')


Bila Anda menggunakan teknik ini, pernyataan SET dapat direvisi sebagai berikut:

- Sebelum:

SET @ temp = N'select * dari penulis di mana au_lname ='''

+ @ Au_lname + N''''

- Setelah:

SET @ temp = N'select * dari penulis di mana au_lname ='''

+ REPLACE (@ au_lname ,'''','''''') + N''''
Injeksi Diaktifkan oleh data Truncation

Setiap dinamis Transact-SQL yang diberikan ke variabel akan dipotong jika lebih besar dari buffer dialokasikan untuk variabel tersebut. Seorang penyerang yang mampu memaksa pemotongan pernyataan dengan melewatkan string terduga lama untuk prosedur yang tersimpan dapat memanipulasi hasilnya. Misalnya, prosedur yang tersimpan yang dibuat oleh script berikut ini rentan terhadap injeksi diaktifkan oleh pemotongan.

CREATE PROSEDUR sp_MySetPassword

@ Loginname sysname,

@ Tua sysname,

@ Baru sysname

SEBAGAI

- Deklarasi variabel.

- Perhatikan bahwa buffer di sini adalah hanya 200 karakter.

MENYATAKAN @ perintah varchar (200)

- Membangun dinamis Transact-SQL.

- Dalam pernyataan berikut, kita perlu total 154 karakter

- Untuk mengatur password 'sa'.

- 26 untuk pernyataan UPDATE, 16 untuk klausa WHERE, 4 untuk 'sa', dan 2 untuk

- Tanda kutip dikelilingi oleh QUOTENAME (@ loginname):

- 200 - 26-16 - 4 - 2 = 154.

- Tapi karena @ baru ini dideklarasikan sebagai sebuah sysname, variabel ini hanya bisa menampung

- 128 karakter.

- Kita dapat mengatasi hal ini dengan mengirimkan beberapa tanda kutip tunggal di @ baru.

SET @ command = 'Pengguna memperbarui set password =' ​​+ QUOTENAME (@ baru,'''') + 'dimana username =' + QUOTENAME (@ loginname,'''') + 'DAN password =' ​​+ QUOTENAME (@ lama ,'''')


- Jalankan perintah.

EXEC (@ command)

GO

Dengan melewati 154 karakter menjadi 128 karakter buffer, penyerang bisa mengatur sandi baru untuk sa tanpa mengetahui password lama.

EXEC sp_MySetPassword 'sa', 'bodoh',

Untuk alasan ini, Anda harus menggunakan buffer besar untuk sebuah variabel perintah atau langsung jalankan Transact-SQL dinamis dalam pernyataan Execute.
Pemotongan Ketika QUOTENAME (@ variabel,'''') dan REPLACE () Apakah Digunakan

String yang dikembalikan oleh QUOTENAME () dan REPLACE () akan diam-diam dipotong jika mereka melebihi ruang yang dialokasikan. Prosedur yang tersimpan yang dibuat dalam contoh berikut menunjukkan apa yang bisa terjadi.

CREATE PROSEDUR sp_MySetPassword

@ Loginname sysname,

@ Tua sysname,

@ Baru sysname

SEBAGAI


- Deklarasi variabel.

MENYATAKAN @ sysname Login

MENYATAKAN @ Newpassword sysname

MENYATAKAN @ Oldpassword sysname

MENYATAKAN @ perintah varchar (2000)


- Dalam pernyataan berikut, data yang disimpan dalam variabel temporer

- Akan dipotong karena ukuran penyangga @ login, @ Oldpassword,

- Dan @ Newpassword hanya 128 karakter, tetapi QUOTENAME () dapat kembali

- Hingga 258 karakter.


SET @ login = QUOTENAME (@ loginname,'''')

SET @ Oldpassword = QUOTENAME (@ lama,'''')

SET @ Newpassword = QUOTENAME (@ baru,'''')


- Membangun dinamis Transact-SQL.

- Jika @ baru berisi 128 karakter, maka akan Newpassword @ '123 ... n

- Di mana n adalah 127 karakter.

- Karena string dikembalikan oleh QUOTENAME () akan dipotong,

- Dapat dibuat agar terlihat seperti pernyataan berikut:

- Pengguna UPDATE SET password = '1234. . . [127] WHERE username = '- hal lain di sini


SET @ command = 'UPDATE Pengguna set password =' ​​+ @ Newpassword

+ 'Dimana username =' + @ login + 'DAN password =' ​​+ @ Oldpassword;


- Jalankan perintah.

EXEC (@ command)

GO

Oleh karena itu, pernyataan berikut akan mengatur password dari semua pengguna untuk nilai yang disahkan dalam kode sebelumnya.

EXEC sp_MyProc'--', 'bodoh',

Anda bisa memaksa pemotongan string dengan melebihi ruang buffer yang dialokasikan bila Anda menggunakan REPLACE (). Prosedur yang tersimpan yang dibuat dalam contoh berikut menunjukkan apa yang bisa terjadi.

CREATE PROSEDUR sp_MySetPassword

@ Loginname sysname,

@ Tua sysname,

@ Baru sysname

SEBAGAI

- Deklarasi variabel.

MENYATAKAN @ sysname Login

MENYATAKAN @ Newpassword sysname

MENYATAKAN @ Oldpassword sysname

MENYATAKAN @ perintah varchar (2000)

- Dalam pernyataan berikut, data akan terpotong karena

- Buffer dialokasikan untuk @ login, @ Oldpassword dan @ Newpassword

- Dapat menyimpan hanya 128 karakter, tetapi QUOTENAME () dapat kembali

- Hingga 258 karakter.


SET @ login = REPLACE (@ loginname,'''','''''')

SET @ Oldpassword = REPLACE (@ tua,'''','''''')

SET @ Newpassword = REPLACE (@ baru,'''','''''')


- Membangun dinamis Transact-SQL.

- Jika @ baru berisi 128 karakter, @ Newpassword akan '123 ... n

- Di mana n adalah 127 karakter.

- Karena string dikembalikan oleh QUOTENAME () akan terpotong, itu

- Dapat dibuat agar terlihat seperti pernyataan berikut:

- Pengguna UPDATE SET password = '1234 ... [127] WHERE username = '- hal lain di sini


SET @ perintah = 'update set password = Pengguna''' + @ Newpassword +'''dimana username ='''

+ @ Login +'''DAN password =''' + @ Oldpassword +'''';


- Jalankan perintah.

EXEC (@ command)

GO

Seperti QUOTENAME (), string pemotongan oleh REPLACE () dapat dihindari dengan menyatakan variabel sementara yang cukup besar untuk semua kasus. Bila mungkin, Anda harus menghubungi QUOTENAME () atau REPLACE () secara langsung di dalam Transact-SQL dinamis. Jika tidak, Anda dapat menghitung ukuran buffer yang dibutuhkan sebagai berikut. Untuk @ outbuffer = QUOTENAME (@ input), ukuran @ outbuffer harus 2 * (len (@ Input) +1). Bila Anda menggunakan REPLACE () dan menggandakan tanda kutip, seperti pada contoh sebelumnya, penyangga 2 * len (@ input) sudah cukup.

Perhitungan berikut ini mencakup semua kasus:

Sementara len (@ find_string)> 0, ukuran yang dibutuhkan buffer =

putaran (len (@ input) / len (@ find_string), 0) * len (@ new_string)

+ (Len (@ input)% len (@ find_string))
Pemotongan Ketika QUOTENAME (@ variabel, ']') Apakah Digunakan

Pemotongan dapat terjadi ketika nama sebuah securable SQL Server akan diteruskan ke pernyataan yang menggunakan bentuk QUOTENAME (@ variabel,']'). Contoh berikut menunjukkan hal ini.

MENCIPTAKAN sp_MyProc PROSEDUR

@ Schemaname sysname,

@ Tablename sysname,

SEBAGAI

- Deklarasikan variabel sebagai sysname. Variabel akan 128 karakter.

- Tapi harus benar-benar @ objectname memungkinkan untuk 2 258 * 1 karakter.

MENYATAKAN @ objectname sysname

SET @ objectname = QUOTENAME (@ schemaname )+'.'+ QUOTENAME (@ tablename)

- Lakukan beberapa operasi.

GO

Ketika Anda concatenating nilai sysname jenis, Anda harus menggunakan variabel sementara cukup besar untuk menampung 128 karakter maksimum per nilai. Jika memungkinkan, panggilan QUOTENAME () secara langsung di dalam Transact-SQL dinamis. Jika tidak, Anda dapat menghitung ukuran buffer yang diperlukan seperti yang dijelaskan pada bagian sebelumnya.

Tidak ada komentar:

Posting Komentar