Menghindari injeksi SQL tanpa parameter

109

Kami sedang berdiskusi lagi di sini tentang penggunaan kueri sql parametrized dalam kode kami. Kami memiliki dua sisi dalam diskusi: Saya dan beberapa orang lain yang mengatakan bahwa kami harus selalu menggunakan parameter untuk melindungi dari suntikan sql dan orang lain yang merasa tidak perlu. Sebaliknya mereka ingin mengganti satu apostrof dengan dua apostrof di semua string untuk menghindari injeksi sql. Semua database kami menjalankan Sql Server 2005 atau 2008 dan basis kode kami berjalan di .NET framework 2.0.

Izinkan saya memberi Anda contoh sederhana di C #:

Saya ingin kami menggunakan ini:

string sql = "SELECT * FROM Users WHERE Name=@name";
SqlCommand getUser = new SqlCommand(sql, connection);
getUser.Parameters.AddWithValue("@name", userName);
//... blabla - do something here, this is safe

Sementara yang lain ingin melakukan ini:

string sql = "SELECT * FROM Users WHERE Name=" + SafeDBString(name);
SqlCommand getUser = new SqlCommand(sql, connection);
//... blabla - are we safe now?

Di mana fungsi SafeDBString didefinisikan sebagai berikut:

string SafeDBString(string inputValue) 
{
    return "'" + inputValue.Replace("'", "''") + "'";
}

Sekarang, selama kami menggunakan SafeDBString pada semua nilai string dalam kueri kami, kami akan aman. Baik?

Ada dua alasan untuk menggunakan fungsi SafeDBString. Pertama, ini adalah cara yang telah dilakukan sejak zaman batu, dan kedua, lebih mudah untuk men-debug pernyataan sql karena Anda melihat kueri excact yang dijalankan pada database.

Sehingga kemudian. Pertanyaan saya adalah apakah benar-benar cukup menggunakan fungsi SafeDBString untuk menghindari serangan injeksi sql. Saya telah mencoba menemukan contoh kode yang melanggar ukuran keamanan ini, tetapi saya tidak dapat menemukan contoh apa pun.

Apakah ada orang di luar sana yang bisa memecahkan ini? Bagaimana Anda melakukannya?

EDIT: Untuk meringkas balasan sejauh ini:

  • Belum ada yang menemukan cara untuk menyiasati SafeDBString di Sql Server 2005 atau 2008. Itu bagus, menurut saya?
  • Beberapa balasan menunjukkan bahwa Anda mendapatkan peningkatan kinerja saat menggunakan kueri parametrized. Alasannya adalah bahwa rencana kueri dapat digunakan kembali.
  • Kami juga setuju bahwa menggunakan kueri parametrized memberikan kode yang lebih mudah dibaca dan lebih mudah dikelola
  • Lebih jauh, lebih mudah untuk selalu menggunakan parameter daripada menggunakan berbagai versi SafeDBString, konversi string ke angka, dan konversi string ke tanggal.
  • Menggunakan parameter Anda mendapatkan konversi jenis otomatis, sesuatu yang sangat berguna ketika kita bekerja dengan tanggal atau angka desimal.
  • Dan terakhir: Jangan mencoba melakukan keamanan sendiri seperti yang ditulis JulianR. Vendor database menghabiskan banyak waktu dan uang untuk keamanan. Tidak ada cara kami dapat melakukan lebih baik dan tidak ada alasan kami harus mencoba melakukan pekerjaan mereka.

Jadi, sementara tidak ada yang bisa merusak keamanan sederhana dari fungsi SafeDBString, saya mendapat banyak argumen bagus lainnya. Terima kasih!

Rune Grimstad
sumber
16
Kolega Anda jauh, jauh, di luar basis. Tantang mereka untuk menemukan satu literatur yang mendukung posisi mereka. Argumen ex neolithos konyol, banyak hal berubah, hanya orang yang terjebak di zaman batu yang gagal beradaptasi.
annakata
1
Yah, setidaknya kolega Anda melindungi terhadap SALAH SATU dari berbagai bentuk peretasan ... Apakah mereka yakin bahwa semua kueri berparameter dapat melakukannya? (Saya tidak ...)
Arjan Einbu
1
Kerentanan apapun tidak akan meyakinkan mereka. Jika Anda membawa beberapa kerentanan (yang Anda minta) dan masalah lain dan menunjukkan satu per satu bahwa parameter akan menyelesaikan masalah itu dan bahwa tim Anda harus menulis rangkaian kode untuk menyediakan sebagian kecil dari fungsionalitas, Anda dapat memenangkan mereka. Semoga berhasil.
Robert Gowland
3
Bahkan tanpa tanda kutip tunggal, Anda masih dapat memecahkan kode Anda dengan logika. Coba gunakan nama pengguna "test OR 1 = 1" - Anda mendapatkan semua baris dikembalikan, bukan hanya yang dengan uji nama pengguna!
Jembatan
1
Mendesah. Saya benar-benar tidak mengerti bagaimana kita sebagai industri bisa terus mentolerir perilaku tidak profesional semacam ini.
jeroenh

Jawaban:

83

Saya pikir jawaban yang benar adalah:

Jangan mencoba melakukan keamanan sendiri . Gunakan pustaka standar industri tepercaya apa pun yang tersedia untuk apa yang Anda coba lakukan, daripada mencoba melakukannya sendiri. Apapun asumsi yang Anda buat tentang keamanan, mungkin saja salah. Seaman apa pun pendekatan Anda (dan terlihat goyah), ada risiko Anda mengabaikan sesuatu dan apakah Anda benar-benar ingin mengambil kesempatan itu dalam hal keamanan?

Gunakan parameter.

JulianR
sumber
Kembali "Gunakan pustaka standar industri tepercaya apa pun yang ada" - dapatkah Anda merekomendasikan satu untuk .NET? Mungkin lebih dari satu tergantung pada DB: SQLServer, MySQL, PostgreSQL? Saya telah mencari SQL-sanitizer tetapi tanpa banyak keberuntungan, jadi dia telah dipaksa untuk menerapkannya sendiri, sebaik mungkin (yang tidak diragukan lagi jauh dari sangat mudah).
PSU
72

Dan kemudian seseorang pergi dan menggunakan "bukan '. Parameternya adalah, IMO, satu-satunya cara yang aman untuk pergi.

Ini juga menghindari banyak masalah i18n dengan tanggal / angka; tanggal berapa 01/02/03? Berapa 123.456? Apakah server Anda (app-server dan db-server) cocok satu sama lain?

Jika faktor risiko tidak meyakinkan mereka, bagaimana dengan kinerja? RDBMS dapat menggunakan kembali rencana kueri jika Anda menggunakan parameter, membantu kinerja. Ini tidak dapat melakukan ini hanya dengan string.

Marc Gravell
sumber
Saya telah mencoba argumen pemformatan dan kinerja, tetapi mereka masih belum yakin.
Rune Grimstad
5
Sebenarnya, sql server dapat menggunakan kembali rencana kueri apakah Anda menggunakan parameter atau tidak. Saya setuju dengan argumen lain, tetapi untuk kebanyakan kasus, argumen kinerja untuk sql berparameter tidak lagi berfungsi.
tnyfst
1
@ tnyfst: apakah dapat menggunakan kembali rencana eksekusi ketika string kueri berubah untuk setiap kombinasi nilai parameter? Saya tidak berpikir itu mungkin.
John Saunders
4
Rencana kueri akan digunakan kembali jika teks kueri identik dengan teks kueri sebelumnya. Jadi jika Anda mengirim permintaan yang SAMA PERSIS dua kali, itu akan digunakan kembali. Namun, jika Anda mengubah bahkan hanya spasi atau koma atau sesuatu, rencana kueri baru harus ditentukan.
marc_s
1
@ Marc: Saya tidak yakin Anda sepenuhnya benar. Hueristik caching SQL Server agak aneh. Parser mampu mengidentifikasi konstanta dalam teks dan dapat mengubah string SQL menjadi salah satu parameter yang digunakan secara artifisial. Ini kemudian dapat memasukkan ke dalam cache teks dari kueri berparameter baru ini. SQL serupa berikutnya mungkin menemukan versi berparameternya cocok di cache. Namun, versi berparameter tidak selalu digunakan dengan versi SQL asli yang sedang di-cache, saya menduga SQL memiliki banyak alasan terkait kinerja untuk memilih di antara dua pendekatan.
AnthonyWJones
27

Argumennya tidak menang. Jika Anda berhasil menemukan kerentanan, rekan kerja Anda hanya akan mengubah fungsi SafeDBString untuk memperhitungkannya dan kemudian meminta Anda untuk membuktikan bahwa ini tidak aman lagi.

Mengingat bahwa kueri parametrized adalah praktik terbaik pemrograman yang tidak perlu dipersoalkan, beban pembuktian harus ada pada mereka untuk menyatakan mengapa mereka tidak menggunakan metode yang lebih aman dan berkinerja lebih baik.

Jika masalahnya adalah menulis ulang semua kode lama, kompromi mudahnya adalah menggunakan kueri parametrized di semua kode baru, dan memfaktor ulang kode lama untuk menggunakannya saat mengerjakan kode itu.

Dugaan saya adalah masalah sebenarnya adalah kesombongan dan keras kepala, dan tidak banyak lagi yang dapat Anda lakukan tentang itu.

Matthew Christensen
sumber
19

Pertama-tama, sampel Anda untuk versi "Ganti" salah. Anda perlu meletakkan apostrof di sekitar teks:

string sql = "SELECT * FROM Users WHERE Name='" + SafeDBString(name) & "'";
SqlCommand getUser = new SqlCommand(sql, connection);

Jadi, itulah satu hal yang parameter lakukan untuk Anda: Anda tidak perlu khawatir tentang apakah suatu nilai perlu diapit tanda kutip atau tidak. Tentu saja, Anda dapat membangunnya ke dalam fungsi, tetapi kemudian Anda perlu menambahkan banyak kerumitan pada fungsi: bagaimana mengetahui perbedaan antara 'NULL' sebagai null dan 'NULL' hanya sebagai string, atau antara angka dan string yang kebetulan berisi banyak digit. Itu hanyalah sumber bug.

Hal lain adalah kinerja: paket kueri berparameter sering di-cache lebih baik daripada paket gabungan, sehingga mungkin menghemat langkah server saat menjalankan kueri.

Selain itu, menghindar dari tanda kutip tunggal tidaklah cukup. Banyak produk DB memungkinkan metode alternatif untuk melarikan diri dari karakter yang dapat dimanfaatkan oleh penyerang. Di MySQL, misalnya, Anda juga dapat melepaskan satu kutipan dengan garis miring terbalik. Jadi nilai "nama" berikut akan meledakkan MySQL hanya dengan SafeDBString()fungsi tersebut, karena saat Anda menggandakan tanda kutip tunggal, kutipan pertama masih lolos oleh garis miring terbalik, meninggalkan yang kedua "aktif":

x \ 'ATAU 1 = 1; -


Juga, JulianR mengemukakan poin bagus di bawah ini: JANGAN PERNAH mencoba melakukan pekerjaan keamanan sendiri. Sangat mudah untuk membuat program keamanan salah dengan cara halus yang tampaknya berhasil, bahkan dengan pengujian menyeluruh. Kemudian waktu berlalu dan setahun kemudian Anda mengetahui bahwa sistem Anda telah retak enam bulan yang lalu dan Anda bahkan tidak pernah menyadarinya sampai saat itu.

Selalu andalkan sebanyak mungkin pada pustaka keamanan yang disediakan untuk platform Anda. Mereka akan ditulis oleh orang-orang yang melakukan kode keamanan untuk mencari nafkah, jauh lebih baik diuji daripada yang dapat Anda kelola, dan dilayani oleh vendor jika kerentanan ditemukan.

Joel Coehoorn
sumber
5
Fungsi ganti menambahkan apostrof
Rune Grimstad
5
Maka itu hanya satu lagi sumber bug. Bagaimana cara mengetahui perbedaan antara NULL sebagai nilai null dan NULL sebagai string teks? Atau antara masukan angka dan string yang kebetulan berisi angka?
Joel Coehoorn
Poin yang bagus. Anda sebaiknya hanya menggunakan fungsi untuk string, dan mungkin tanggal, jadi Anda harus berhati-hati. Itulah satu lagi alasan untuk menggunakan parameter! Yay!
Rune Grimstad
10

Jadi saya akan mengatakan:

1) Mengapa Anda mencoba menerapkan kembali sesuatu yang sudah ada di dalamnya? itu ada di sana, tersedia, mudah digunakan dan sudah di-debug pada skala global. Jika ditemukan bug di masa mendatang, bug tersebut akan diperbaiki dan tersedia untuk semua orang dengan sangat cepat tanpa Anda harus melakukan apa pun.

2) Proses apa yang ada untuk menjamin bahwa Anda tidak pernah melewatkan panggilan ke SafeDBString? Kehilangannya hanya di 1 tempat dapat membuka banyak masalah. Seberapa besar Anda akan mengamati hal-hal ini, dan mempertimbangkan seberapa banyak usaha yang sia-sia ketika jawaban benar yang diterima begitu mudah dijangkau.

3) Seberapa yakin Anda bahwa Anda telah menutupi setiap vektor serangan yang diketahui Microsoft (penulis DB dan perpustakaan akses) dalam implementasi SafeDBString Anda ...

4) Seberapa mudah membaca struktur sql? Contoh menggunakan + concatenation, parameternya sangat mirip dengan string.Format, yang lebih mudah dibaca.

Selain itu, ada 2 cara untuk mengetahui apa yang sebenarnya dijalankan - gulirkan fungsi LogCommand Anda sendiri, fungsi sederhana tanpa masalah keamanan , atau bahkan lihat jejak sql untuk mengetahui apa yang menurut database sebenarnya sedang terjadi.

Fungsi LogCommand kami sederhana:

    string LogCommand(SqlCommand cmd)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(cmd.CommandText);
        foreach (SqlParameter param in cmd.Parameters)
        {
            sb.Append(param.ToString());
            sb.Append(" = \"");
            sb.Append(param.Value.ToString());
            sb.AppendLine("\"");
        }
        return sb.ToString();
    }

Benar atau salah, ini memberi kita informasi yang kita butuhkan tanpa masalah keamanan.

Jim T
sumber
1
Dia mungkin harus berurusan dengan sekelompok programmer VBSCRIPT lama yang terbiasa melakukan segalanya, termasuk XML dan SQL, melalui penggabungan string. Ini akan menjadi orang-orang yang takut dengan penggunaan API. Tidak banyak yang bisa dilakukan dengan mereka, setidaknya tidak ada yang manusiawi.
John Saunders
1
+1 untuk item # 2, dengan pengecualian bahwa tidak ada cara untuk menerapkan parameter nyata juga.
Joel Coehoorn
7

Dengan kueri berparameter, Anda mendapatkan lebih dari sekadar perlindungan terhadap injeksi sql. Anda juga mendapatkan potensi cache rencana eksekusi yang lebih baik. Jika Anda menggunakan sql server query profiler, Anda masih dapat melihat 'persis sql yang dijalankan di database' sehingga Anda tidak benar-benar kehilangan apa pun dalam hal men-debug pernyataan sql Anda.

Steve Willcock
sumber
MySQL juga mencatat kueri berparameter dengan nilai param yang diinterpolasi ke dalamnya.
Bill Karwin
5

Saya telah menggunakan kedua pendekatan untuk menghindari serangan injeksi SQL dan pasti lebih memilih kueri parametrized. Ketika saya telah menggunakan kueri gabungan, saya telah menggunakan fungsi perpustakaan untuk melarikan diri dari variabel (seperti mysql_real_escape_string) dan tidak akan yakin saya telah membahas semuanya dalam implementasi berpemilik (sepertinya Anda juga).

RedBlueThing
sumber
2
+1 karena mysql_real_escape_string () lolos \ x00, \ x1a, \ n \ r 'dan ". Ini juga menangani masalah kumpulan karakter. Fungsi naif rekan kerja OP tidak melakukan semua itu!
Bill Karwin
4

Anda tidak dapat dengan mudah melakukan pemeriksaan jenis apa pun pada input pengguna tanpa menggunakan parameter.

Jika Anda menggunakan kelas SQLCommand dan SQLParameter untuk melakukan panggilan DB, Anda masih dapat melihat kueri SQL yang sedang dijalankan. Lihat properti CommandText SQLCommand.

Saya selalu menjadi tersangka kecil dari pendekatan roll-your-own untuk mencegah injeksi SQL ketika kueri berparameter sangat mudah digunakan. Kedua, hanya karena "selalu dilakukan dengan cara itu" tidak berarti itu cara yang benar untuk melakukannya.

Tim Scarborough
sumber
3

Ini hanya aman jika Anda dijamin akan mengirimkan string.

Bagaimana jika Anda tidak memasukkan string di beberapa titik? Bagaimana jika Anda hanya memberikan satu nomor?

http://www.mywebsite.com/profile/?id=7;DROP DATABASE DB

Pada akhirnya akan menjadi:

SELECT * FROM DB WHERE Id = 7;DROP DATABASE DB
joshcomley
sumber
Bisa berupa string atau angka. Sebuah string di-escape dengan SafeDbString. Angka adalah Int32, dan itu tidak bisa menjatuhkan database.
Andomar
Angka lebih mudah ditangani. Anda baru saja mengonversi parameter menjadi int / float / apa pun sebelum menggunakannya dalam kueri. Masalahnya adalah ketika Anda harus menerima data string.
Rune Grimstad
Andomar - jika Anda hanya membuat pernyataan SQL dengan tangan maka "tipe" yang dimaksudkan tidak masalah, Anda dapat menyuntikkan SQL dengan angka dengan sangat, sangat mudah. Rune - Saya pikir ini terlalu mengandalkan pengembang individu untuk mengingat semua nuansa memecahkan injeksi SQL secara manual. Jika Anda hanya mengatakan "gunakan parameter", itu sangat sederhana dan tidak mungkin salah.
joshcomley
@Andomar: Bagaimana dengan NULL? Atau string yang terlihat seperti angka?
Joel Coehoorn
2

Saya akan menggunakan prosedur atau fungsi tersimpan untuk semuanya, jadi pertanyaannya tidak akan muncul.

Di mana saya harus memasukkan SQL ke dalam kode, saya menggunakan parameter, yang merupakan satu-satunya hal yang masuk akal. Ingatkan para pembangkang bahwa ada peretas yang lebih pintar dari mereka, dan dengan insentif yang lebih baik untuk memecahkan kode yang mencoba mengakali mereka. Menggunakan parameter, itu tidak mungkin, dan itu tidak sulit.

John Saunders
sumber
Ok, bagaimana cara melakukan injeksi SQL menggunakan parameter?
John Saunders
@Saunders: Langkah 1 adalah menemukan bug buffer overflow dalam fungsionalitas penanganan parameter DB Anda.
Brian
2
Sudah menemukan satu? Dalam DB komersial yang ditumbuk oleh ratusan ribu peretas setiap hari? Salah satu yang dibuat oleh perusahaan software terkenal memiliki kantong yang sangat dalam? Anda dapat mengutip gugatan dengan nama jika ini memungkinkan.
John Saunders
1
Tentu saja, jika SPROC menggunakan penggabungan dan EXEC (bukan sp_ExecuteSQL) Anda kembali dalam masalah ... (Saya telah melihatnya melakukan kesalahan terlalu sering untuk mengabaikannya ...)
Marc Gravell
2

Setuju dengan sangat tentang masalah keamanan.
Alasan lain untuk menggunakan parameter adalah untuk efisiensi.

Database akan selalu mengkompilasi kueri Anda dan menyimpannya dalam cache, kemudian menggunakan kembali kueri yang di-cache (yang jelas lebih cepat untuk permintaan berikutnya). Jika Anda menggunakan parameter, meskipun Anda menggunakan parameter yang berbeda, database akan menggunakan kembali kueri yang di-cache karena cocok berdasarkan string SQL sebelum mengikat parameter.

Namun jika Anda tidak mengikat parameter maka string SQL berubah pada setiap permintaan (yang memiliki parameter berbeda) dan itu tidak akan pernah cocok dengan apa yang ada di cache Anda.

Darren Greaves
sumber
2

Untuk alasan yang sudah diberikan, parameter adalah ide yang sangat bagus. Tapi kami benci menggunakannya karena membuat param dan menetapkan namanya ke variabel untuk digunakan nanti dalam kueri adalah kerusakan kepala tiga arah.

Kelas berikut membungkus stringbuilder yang biasanya akan Anda gunakan untuk membuat permintaan SQL. Ini memungkinkan Anda menulis kueri paramater tanpa harus membuat parameter , sehingga Anda dapat berkonsentrasi pada SQL. Kode Anda akan terlihat seperti ini ...

var bldr = new SqlBuilder( myCommand );
bldr.Append("SELECT * FROM CUSTOMERS WHERE ID = ").Value(myId, SqlDbType.Int);
//or
bldr.Append("SELECT * FROM CUSTOMERS WHERE NAME LIKE ").FuzzyValue(myName, SqlDbType.NVarChar);
myCommand.CommandText = bldr.ToString();

Keterbacaan kode, saya harap Anda setuju, sangat ditingkatkan, dan hasilnya adalah kueri berparameter yang tepat.

Kelasnya terlihat seperti ini ...

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace myNamespace
{
    /// <summary>
    /// Pour le confort et le bonheur, cette classe remplace StringBuilder pour la construction
    /// des requêtes SQL, avec l'avantage qu'elle gère la création des paramètres via la méthode
    /// Value().
    /// </summary>
    public class SqlBuilder
    {
        private StringBuilder _rq;
        private SqlCommand _cmd;
        private int _seq;
        public SqlBuilder(SqlCommand cmd)
        {
            _rq = new StringBuilder();
            _cmd = cmd;
            _seq = 0;
        }
        //Les autres surcharges de StringBuilder peuvent être implémenté ici de la même façon, au besoin.
        public SqlBuilder Append(String str)
        {
            _rq.Append(str);
            return this;
        }
        /// <summary>
        /// Ajoute une valeur runtime à la requête, via un paramètre.
        /// </summary>
        /// <param name="value">La valeur à renseigner dans la requête</param>
        /// <param name="type">Le DBType à utiliser pour la création du paramètre. Se référer au type de la colonne cible.</param>
        public SqlBuilder Value(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append(paramName);
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this;
        }
        public SqlBuilder FuzzyValue(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append("'%' + " + paramName + " + '%'");
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this; 
        }

        public override string ToString()
        {
            return _rq.ToString();
        }
    }
}
bbsimonbb
sumber
1

Dari waktu yang sangat singkat saya harus menyelidiki masalah injeksi SQL, saya dapat melihat bahwa membuat nilai 'aman' juga berarti Anda menutup pintu ke situasi di mana Anda mungkin benar-benar menginginkan apostrof dalam data Anda - bagaimana dengan nama seseorang , misalnya O'Reilly.

Itu meninggalkan parameter dan prosedur yang tersimpan.

Dan ya, Anda harus selalu mencoba menerapkan kode dengan cara terbaik yang Anda ketahui sekarang - tidak hanya bagaimana kode selalu dilakukan.

quamrana
sumber
Tanda kutip ganda akan diterjemahkan oleh server sql menjadi satu tanda kutip tunggal, jadi O'Reilly akan diterjemahkan menjadi Name = 'O''Reilly'
Rune Grimstad
Jadi apakah ada fungsi yang sesuai untuk menghapus apostrof ketika pengguna ingin melihat datanya?
quamrana
Tidak dibutuhkan. Urutan escape memungkinkan parser untuk melihat kutipan tunggal daripada akhir string. Saat penguraian, ini dilihat ''sebagai literal ', jadi string Anda akan terlihat secara internal sebagai urutan karakter O'Reilly. Itulah yang akan disimpan, diambil, dibandingkan oleh DB, dll. Jika Anda ingin menampilkan data kepada pengguna setelah Anda meloloskan diri, simpan salinan appside string yang tidak lolos.
cHao
1

Berikut adalah beberapa artikel yang mungkin berguna bagi Anda untuk meyakinkan rekan kerja Anda.

http://www.sommarskog.se/dynamic_sql.html

http://unixwiz.net/techtips/sql-injection.html

Secara pribadi saya lebih suka tidak pernah mengizinkan kode dinamis untuk menyentuh database saya, mengharuskan semua kontak harus melalui sps (dan bukan yang menggunakan SQl dinamis). Ini berarti tidak ada yang dapat dilakukan kecuali apa yang telah saya berikan izin kepada pengguna dan bahwa pengguna internal (kecuali sangat sedikit dengan akses produksi untuk tujuan admin) tidak dapat langsung mengakses tabel saya dan membuat kekacauan, mencuri data, atau melakukan penipuan. Jika Anda menjalankan aplikasi keuangan, ini adalah cara teraman.

HLGEM
sumber
1

Itu bisa rusak, namun caranya tergantung pada versi / tambalan yang tepat dll.

Salah satu yang telah muncul adalah bug overflow / truncation yang dapat dieksploitasi.

Cara lain di masa mendatang adalah menemukan bug yang mirip dengan database lain - misalnya tumpukan MySQL / PHP mengalami masalah pelolosan karena urutan UTF8 tertentu dapat digunakan untuk memanipulasi fungsi ganti - fungsi ganti akan ditipu untuk memperkenalkan karakter injeksi.

Pada akhirnya, mekanisme keamanan pengganti bergantung pada fungsionalitas yang diharapkan tetapi tidak dimaksudkan . Karena fungsionalitas tersebut bukanlah tujuan yang dimaksudkan dari kode, ada kemungkinan besar bahwa beberapa quirk yang ditemukan akan merusak fungsionalitas yang Anda harapkan.

Jika Anda memiliki banyak kode lama, metode ganti dapat digunakan sebagai pengganti untuk menghindari penulisan ulang dan pengujian yang lama. Jika Anda menulis kode baru, tidak ada alasan.

David
sumber
1

Selalu gunakan kueri berparameter jika memungkinkan. Kadang-kadang bahkan masukan sederhana tanpa menggunakan karakter aneh sudah dapat membuat injeksi SQL jika tidak diidentifikasi sebagai masukan untuk bidang dalam database.

Jadi biarkan database melakukan tugasnya untuk mengidentifikasi input itu sendiri, belum lagi itu juga menghemat pembagian masalah ketika Anda benar-benar perlu memasukkan karakter aneh yang jika tidak akan lolos atau diubah. Ia bahkan dapat menghemat beberapa runtime yang berharga pada akhirnya karena tidak harus menghitung input.

VulstaR
sumber
1

Saya tidak melihat ada penjawab lain yang membahas sisi 'mengapa melakukannya sendiri itu buruk', tetapi pertimbangkan serangan SQL Truncation .

Ada juga fungsi QUOTENAMET-SQL yang dapat membantu jika Anda tidak dapat meyakinkan mereka untuk menggunakan params. Ini menangkap banyak (semua?) Kekhawatiran qoute yang lolos.

JasonRShaver
sumber
1

2 tahun kemudian , saya residivated ... Siapapun yang menemukan parameter yang menyakitkan dipersilakan untuk mencoba Ekstensi VS saya, QueryFirst . Anda mengedit permintaan Anda dalam file .sql nyata (Validasi, Intellisense). Untuk menambahkan parameter, Anda cukup mengetiknya langsung ke SQL Anda, dimulai dengan '@'. Saat Anda menyimpan file, QueryFirst akan membuat kelas pembungkus untuk memungkinkan Anda menjalankan kueri dan mengakses hasilnya. Ini akan mencari tipe DB dari parameter Anda dan memetakannya ke tipe .net, yang akan Anda temukan sebagai input ke metode Execute () yang dihasilkan. Tidak bisa lebih sederhana. Melakukannya dengan cara yang benar secara radikal lebih cepat dan lebih mudah daripada melakukannya dengan cara lain, dan membuat kerentanan injeksi sql menjadi tidak mungkin, atau setidaknya sangat sulit. Ada keuntungan mematikan lainnya, seperti dapat menghapus kolom di DB Anda dan segera melihat kesalahan kompilasi dalam aplikasi Anda.

penafian hukum: Saya menulis QueryFirst

bbsimonbb
sumber
0

Berikut beberapa alasan untuk menggunakan kueri berparameter:

  1. Keamanan - Lapisan akses database tahu cara menghapus atau menghindari item yang tidak diperbolehkan dalam data.
  2. Pemisahan masalah - Kode saya tidak bertanggung jawab untuk mengubah data menjadi format yang disukai database.
  3. Tidak ada redundansi - Saya tidak perlu menyertakan assembly atau class di setiap project yang melakukan pemformatan / pelolosan database ini; itu dibangun di perpustakaan kelas.
Powerlord
sumber
0

Ada beberapa kerentanan (saya tidak dapat mengingat database mana itu) yang terkait dengan buffer overflow dari pernyataan SQL.

Apa yang ingin saya katakan adalah, SQL-Injection lebih dari sekedar "escape the quote", dan Anda tidak tahu apa yang akan terjadi selanjutnya.

Dennis C
sumber
0

Pertimbangan penting lainnya adalah melacak data yang lolos dan tidak lolos. Ada banyak sekali aplikasi, Web dan lainnya, yang tampaknya tidak benar-benar melacak kapan data dalam bentuk mentah-Unicode, & -enkode, HTML yang diformat, dan lain-lain. Jelas bahwa akan menjadi sulit untuk melacak string mana yang - ''disandikan dan mana yang tidak.

Ini juga masalah ketika Anda akhirnya mengubah jenis beberapa variabel - mungkin dulu adalah bilangan bulat, tetapi sekarang menjadi string. Sekarang Anda punya masalah.

Paul Fisher
sumber