Parametreler olmadan SQL enjeksiyonundan kaçınmak


109

Burada, kodumuzda parametrize sql sorgularının kullanılmasıyla ilgili başka bir tartışma yapıyoruz. Tartışmada iki tarafımız var: Ben ve diğerleri, sql enjeksiyonlarına karşı koruma sağlamak için her zaman parametreleri kullanmamız gerektiğini söyleyenler ve gerekli olmadığını düşünen diğer kişiler. Bunun yerine, sql enjeksiyonlarını önlemek için tek kesme işaretini tüm dizelerde iki kesme işaretiyle değiştirmek istiyorlar. Veritabanlarımızın tümü Sql Server 2005 veya 2008 ile çalışıyor ve kod tabanımız .NET framework 2.0 üzerinde çalışıyor.

C # ile size basit bir örnek vereyim:

Bunu kullanmamızı istiyorum:

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

Diğerleri bunu yapmak isterken:

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

SafeDBString işlevi aşağıdaki gibi tanımlandığında:

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

Şimdi, sorgularımızdaki tüm string değerlerinde SafeDBString kullandığımız sürece güvende olmalıyız. Sağ?

SafeDBString işlevini kullanmanın iki nedeni vardır. Birincisi, taş eskidiğinden beri yapılan budur ve ikincisi, veritabanında çalıştırılan tam sorguyu gördüğünüz için sql ifadelerinde hata ayıklamak daha kolaydır.

E sonra. Sorum, sql enjeksiyon saldırılarını önlemek için SafeDBString işlevini kullanmanın gerçekten yeterli olup olmadığıdır. Bu güvenlik önlemini bozan kod örnekleri bulmaya çalışıyordum, ancak hiçbir örneğini bulamıyorum.

Bunu kırabilecek kimse var mı? Nasıl yapardın?

DÜZENLEME: Şimdiye kadarki cevapları özetlemek gerekirse:

  • Henüz kimse Sql Server 2005 veya 2008'de SafeDBString'i aşmanın bir yolunu bulamadı. Sanırım bu iyi mi?
  • Birkaç yanıt, parametreleştirilmiş sorgular kullandığınızda bir performans kazancı elde ettiğinizi belirtti. Bunun nedeni, sorgu planlarının yeniden kullanılabilmesidir.
  • Ayrıca parametreleştirilmiş sorguları kullanmanın, bakımı daha kolay olan daha okunabilir kodlar verdiğini kabul ediyoruz.
  • Dahası, parametreleri kullanmak, SafeDBString'in çeşitli sürümlerini, diziden numaraya dönüştürmeleri ve tarihe kadar dönüştürmeleri kullanmaktan daha kolaydır.
  • Parametreleri kullanarak otomatik tür dönüşümü elde edersiniz, bu özellikle tarihlerle veya ondalık sayılarla çalışırken yararlı olan bir şeydir.
  • Ve son olarak: JulianR'ın yazdığı gibi güvenliği kendiniz yapmaya çalışmayın . Veritabanı satıcıları güvenlik için çok fazla zaman ve para harcıyor. Daha iyisini yapabilmemizin hiçbir yolu yok ve işlerini yapmaya çalışmamız için hiçbir neden yok.

Bu nedenle, SafeDBString işlevinin basit güvenliğini kimse kıramasa da birçok başka iyi argüman aldım. Teşekkürler!


16
Meslektaşlarınız yolun dışında. Konumlarını destekleyen tek bir literatür bulmaları için onlara meydan okuyun. Ex neolithos argümanı gülünçtür, işler değişir, sadece taş devrinde sıkışmış bir kişi uyum sağlayamaz.
annakata

1
Pekala, en azından meslektaşlarınız farklı hack biçimlerinden BİRİNE karşı koruma sağlıyorlar ... Parametreli tüm sorguların işe yaradığından eminler mi? (Değilim ...)
Arjan Einbu

1
Herhangi bir güvenlik açığı onları ikna etmeyecektir. Birkaç güvenlik açığı (istediğiniz şey budur) ve diğer sorunları getirir ve tek tek parametrelerin bu sorunu çözeceğini ve ekibinizin işlevselliğin bir kısmını sağlamak için çok sayıda kod yazması gerekeceğini belirtirseniz, onları kazan. İyi şanslar.
Robert Gowland

3
Tek tırnak işaretleri olmadan bile, kodunuzu mantıkla kırabilirsiniz. "Test OR 1 = 1" kullanıcı adını kullanmayı deneyin - yalnızca kullanıcı adı testini içeren satırlar yerine tüm satırları döndürürsünüz!
Bridge

1
İç çekmek. Bir endüstri olarak bu tür profesyonel olmayan davranışlara tolerans göstermeyi nasıl başardığımızı gerçekten anlamıyorum.
jeroenh

Yanıtlar:


83

Sanırım doğru cevap:

Güvenliği kendiniz yapmaya çalışmayın . Kendiniz yapmaya çalışmak yerine, yapmaya çalıştığınız şey için mevcut güvenilir, endüstri standardı kitaplığı kullanın . Güvenlik konusunda yaptığınız varsayımlar yanlış olabilir. Kendi yaklaşımınız ne kadar güvenli görünse de (ve en iyi ihtimalle titrek görünebilir), bir şeyi gözden kaçırma riskiniz var ve güvenlik söz konusu olduğunda gerçekten bu şansı kullanmak istiyor musunuz?

Parametreleri kullanın.


Yeniden "Güvenilir, endüstri standardı kitaplığı kullanın" - .NET için bir tane önerebilir misiniz? Belki de DB'ye bağlı olarak birden fazla: SQLServer, MySQL, PostgreSQL? SQL dezenfektanı aradım ama şansım yaver gitmedi, bu yüzden elimden geldiğince kendiminkini uygulamak zorunda kaldım (ki bu hiç şüphesiz kusursuz olmaktan çok uzaktır).
PSU

72

Ve sonra birisi "yerine" gider ve kullanır. Parametreler, IMO, gitmenin tek güvenli yoludur.

Ayrıca tarihler / sayılarla ilgili birçok i18n sorununu da önler; 01/02/03 hangi tarih? 123.456 ne kadar? Sunucularınız (uygulama-sunucu ve db-sunucu) birbirleriyle aynı fikirde mi?

Risk faktörü onları ikna etmiyorsa, performans nasıl olur? Parametreleri kullanırsanız RDBMS, performansa yardımcı olarak sorgu planını yeniden kullanabilir. Bunu sadece ip ile yapamaz.


Biçimlendirme ve performans argümanlarını denedim, ancak yine de ikna olmadılar.
Rune Grimstad

5
Aslında sql server, parametre kullansanız da kullanmasanız da sorgu planını yeniden kullanabilir. Diğer argümanlara katılıyorum, ancak çoğu durumda parametreli sql için performans argümanı artık çalışmıyor.
tnyfst

1
@tnyfst: sorgu dizesi her parametre değeri kombinasyonu için değiştiğinde yürütme planını yeniden kullanabilir mi? Bunun mümkün olduğunu düşünmedim.
John Saunders

4
Sorgu metni daha önceki bir sorgu metnine KİMLİK ise, sorgu planı yeniden kullanılacaktır. Dolayısıyla, TAM AYNI sorguyu iki kez gönderirseniz, yeniden kullanılacaktır. Ancak, sadece bir boşluk veya virgül veya başka bir şeyi bile değiştirirseniz, yeni bir sorgu planının belirlenmesi gerekecektir.
marc_s

1
@Marc: Tamamen doğru olduğundan emin değilim. Geçmişi önbelleğe alan SQL Sunucuları biraz garip. Ayrıştırıcı, metindeki sabitleri tanımlayabilir ve SQL dizesini yapay olarak parametreleri kullanan birine dönüştürebilir. Daha sonra bu yeni parametreli sorgunun metnini önbelleğe ekleyebilir. Sonraki benzer SQL, önbellekte eşleşen parametreleştirilmiş sürümünü bulabilir. Bununla birlikte, parametreleştirilmiş sürümler her zaman orijinal SQL sürümleri önbelleğe alınarak kullanılmaz, SQL'in iki yaklaşım arasında seçim yapmak için performansla ilgili milyonlarca nedeni olduğundan şüpheleniyorum.
AnthonyWJones

27

Argüman kazanılamaz. Bir güvenlik açığı bulmayı başarırsanız, iş arkadaşlarınız SafeDBString işlevini bunu hesaba katacak şekilde değiştirecek ve ardından sizden bunun güvenli olmadığını yeniden kanıtlamanızı isteyecektir.

Parametreleştirilmiş sorguların tartışmasız bir programlama en iyi uygulaması olduğu düşünüldüğünde, neden hem daha güvenli hem de daha iyi performans gösteren bir yöntemi kullanmadıklarını belirtmek için ispat yükü onların üzerinde olmalıdır.

Sorun tüm eski kodu yeniden yazmaksa, kolay uzlaşma, tüm yeni kodda parametreleştirilmiş sorgular kullanmak ve bu kod üzerinde çalışırken bunları kullanmak için eski kodu yeniden düzenlemek olacaktır.

Benim tahminim asıl mesele gurur ve inatçılık ve bu konuda yapabileceğiniz pek bir şey yok.


19

Her şeyden önce, "Değiştir" sürümü için örneğiniz yanlış. Metnin etrafına kesme işareti koymanız gerekir:

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

Bu, parametrelerin sizin için yaptığı diğer bir şeydir: bir değerin tırnak içine alınması gerekip gerekmediği konusunda endişelenmenize gerek yoktur. Elbette, bunu işleve yerleştirebilirsiniz, ancak sonra işleve çok fazla karmaşıklık eklemeniz gerekir: 'NULL' ile sadece bir dize olarak 'NULL' arasındaki veya bir sayı ile sayı arasındaki farkı nasıl anlayabilirsiniz? sadece çok sayıda rakam içeren bir dize. Bu sadece böcekler için başka bir kaynak.

Diğer bir şey ise performanstır: parametreli sorgu planları genellikle birleştirilmiş planlardan daha iyi önbelleğe alınır, bu nedenle belki de sunucuyu sorguyu çalıştırırken bir adım kurtarır.

Ek olarak, tek tırnak işaretlerinden kaçmak yeterince iyi değildir. Birçok DB ürünü, bir saldırganın yararlanabileceği karakterlerden kaçmak için alternatif yöntemlere izin verir. Örneğin MySQL'de ters eğik çizgi ile tek bir alıntıdan da kaçabilirsiniz. Ve böylece aşağıdaki "isim" değeri MySQL'i sadece SafeDBString()fonksiyonla havaya uçuracaktır , çünkü tek alıntıyı iki katına çıkardığınızda, birincisi hala ters eğik çizgi ile önlenerek 2. olanı "aktif" bırakarak:

x \ 'VEYA 1 = 1; -


Ayrıca, JulianR aşağıda iyi bir noktaya değiniyor: ASLA güvenlik çalışmasını kendiniz yapmaya çalışmayın. Kapsamlı testlerle bile güvenlik programlamasını işe yarıyor gibi görünen ince şekillerde yanlış yapmak çok kolaydır . Sonra zaman geçer ve bir yıl sonra, sisteminizin altı ay önce kırıldığını öğrenirsiniz ve o zamana kadar bunu asla bilmiyordunuz.

Platformunuz için sağlanan güvenlik kitaplıklarına her zaman mümkün olduğunca güvenin. Geçim için güvenlik kodu yapan, yönetebileceğinizden çok daha iyi test edilen kişiler tarafından yazılacak ve bir güvenlik açığı bulunursa satıcı tarafından hizmete sunulacaktır.


5
Değiştirme işlevi kesme işaretlerini ekler
Rune Grimstad

5
O zaman bu sadece bir hata kaynağı daha. Boş değer olarak NULL ile metin dizesi olarak NULL arasındaki farkı nasıl biliyor? Ya da bir sayı girişi ile sadece rakam içeren bir dizge arasında mı?
Joel Coehoorn

İyi bir nokta. Bu işlevi yalnızca dizeler ve muhtemelen tarihler için kullanmalısınız, bu nedenle dikkatli olmalısınız. Parametreleri kullanmak için bir neden daha var! Yaşasın!
Rune Grimstad

10

Yani şunu söyleyebilirim:

1) Neden yerleşik olan bir şeyi yeniden uygulamaya çalışıyorsunuz? orada, hazır, kullanımı kolay ve küresel ölçekte zaten hata ayıklaması yapılmış. İçinde gelecekteki hatalar bulunursa, bunlar düzeltilecek ve siz hiçbir şey yapmanıza gerek kalmadan çok hızlı bir şekilde herkes tarafından kullanılabilir.

2) SafeDBString'e yapılan bir çağrıyı asla kaçırmamanızı garanti etmek için hangi işlemler uygulanmaktadır ? Sadece 1 yerde gözden kaçırmak pek çok sorunu ortaya çıkarabilir. Bu şeylere ne kadar göz kulak olacaksınız ve kabul edilen doğru cevaba ulaşmak çok kolayken bu çabanın ne kadar boşa gittiğini düşünün.

3) Microsoft'un (DB'nin ve erişim kitaplığının yazarı) SafeDBString uygulamanızda bildiği her saldırı vektörünü örttüğünüzden ne kadar eminsiniz ...

4) Sql'nin yapısını okumak ne kadar kolay? Örnek + birleştirme kullanır, parametreler daha okunaklı olan string.Format'a çok benzer.

Ayrıca, gerçekte neyin çalıştırıldığını anlamanın 2 yolu vardır - kendi LogCommand işlevinizi, güvenlik kaygısı olmayan basit bir işlevi yuvarlayın , hatta veritabanının gerçekte ne olduğunu düşündüğünü bulmak için bir sql izine bakın.

LogCommand işlevimiz basitçe:

    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();
    }

Doğru ya da yanlış, bize güvenlik sorunları olmadan ihtiyacımız olan bilgileri verir.


1
Muhtemelen, XML ve SQL dahil her şeyi dize birleştirme yoluyla yapmaya alışmış bir grup eski VBSCRIPT programcısıyla uğraşmak zorunda. Bunlar, bir API kullanımından korkan kişiler olacaktır. Onlarla yapılabilecek pek bir şey yok, en azından insani bir şey yok.
John Saunders

1
Gerçek parametreleri zorlamanın da bir yolu olmaması dışında, 2. öğe için +1.
Joel Coehoorn

7

Parametreli sorgular ile sql enjeksiyonuna karşı korumadan daha fazlasını elde edersiniz. Ayrıca daha iyi bir yürütme planı önbelleğe alma potansiyeli elde edersiniz. Sql sunucu sorgu profilleyicisini kullanırsanız, hala 'veritabanında çalıştırılan tam sql'yi' görebilirsiniz, böylece sql ifadelerinizde hata ayıklama açısından gerçekten hiçbir şey kaybetmezsiniz.


MySQL ayrıca, içlerine enterpolasyonlu param değerleriyle parametreli sorguları da günlüğe kaydeder.
Bill Karwin

5

SQL enjeksiyon saldırılarını önlemek için her iki yaklaşımı da kullandım ve kesinlikle parametrik sorguları tercih ediyorum. Birleştirilmiş sorgular kullandığımda, değişkenlerden kaçmak için bir kütüphane işlevi kullandım (mysql_real_escape_string gibi) ve her şeyi özel bir uygulamada ele aldığımdan emin değilim (siz de öyle görünüyorsunuz).


2
+1 çünkü mysql_real_escape_string () \ x00, \ x1a, \ n \ r 've "kaçar. Ayrıca karakter seti sorunlarını da ele alır. OP'nin iş arkadaşlarının saf işlevi bunların hiçbirini yapmaz!
Bill Karwin

4

Parametreleri kullanmadan kullanıcı girdisinin herhangi bir tür kontrolünü kolayca yapamazsınız.

DB çağrıları yapmak için SQLCommand ve SQLParameter sınıflarını kullanırsanız, yürütülen SQL sorgusunu yine de görebilirsiniz. SQLCommand'ın CommandText özelliğine bakın.

Parametreli sorguların kullanımı çok kolay olduğunda, SQL enjeksiyonunu önlemeye yönelik kendi yaklaşımını kendin yap yaklaşımından her zaman biraz şüpheliyim. İkincisi, "her zaman bu şekilde yapıldığı" için, bunu yapmanın doğru yolu olduğu anlamına gelmez.


3

Bu, yalnızca bir dizeyi geçeceğiniz garanti edilirse güvenlidir.

Ya bir noktada bir dizeyi geçmiyorsan? Ya sadece bir sayı iletirseniz?

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

Sonuçta şu hale gelecekti:

SELECT * FROM DB WHERE Id = 7;DROP DATABASE DB

Ya bir dizge ya da sayı. SafeDbString ile bir dizeden kaçılır. Bir sayı bir Int32'dir ve veritabanlarını bırakamaz.
Andomar

Sayıların kullanımı daha kolaydır. Sorguda kullanmadan önce parametreyi int / float / her neyse ona dönüştürürsünüz. Sorun, dizi verilerini kabul etmeniz gerektiğinde ortaya çıkar.
Rune Grimstad

Andomar - eğer elle bir SQL ifadesi oluşturuyorsanız, o zaman amaçlanan "tip" önemli değildir, SQL çok, çok kolay bir şekilde bir sayı enjekte edebilirsiniz. Rune - Bence bu, bireysel geliştiricinin SQL enjeksiyonunu manuel olarak çözmenin tüm nüanslarını hatırlaması için çok fazla güveniyor. Sadece "parametreleri kullan" derseniz, çok basittir ve yanlış gidemezler.
joshcomley

@Andomar: NULL ne olacak? Veya sayılara benzeyen dizeler?
Joel Coehoorn

2

Her şey için depolanan prosedürleri veya işlevleri kullanırdım, böylece soru ortaya çıkmazdı.

SQL'i koda koymam gereken yerlerde, mantıklı olan tek şey olan parametreleri kullanıyorum. Muhaliflere, kendilerinden daha akıllı hackerlar olduğunu ve onları alt etmeye çalışan kodu kırmak için daha iyi bir teşvikle hatırlatın. Parametreleri kullanmak mümkün değil ve hiç de zor değil.


Tamam, parametreleri kullanarak SQL enjeksiyonu nasıl yapılır?
John Saunders

@Saunders: Adım 1, DB'nizin parametre işleme işlevselliğinde bir arabellek taşması hatası bulmaktır.
Brian

2
Henüz bir tane buldunuz mu? Her gün yüzbinlerce hacker tarafından ezilen ticari bir DB'de mi? Çok derin cepleri olduğu bilinen bir yazılım şirketi tarafından yapılmış olanı mı? Bu mümkün olsaydı, davayı ismiyle alıntı yapabilirsiniz .
John Saunders

1
Elbette, SPROC birleştirme ve EXEC kullanırsa (sp_ExecuteSQL yerine) başınız belaya girer ... (Bunu azaltmak için pek çok kez yanlış yapıldığını gördüm ...)
Marc Gravell

2

Güvenlik konularında büyük ölçüde anlaşın.
Parametreleri kullanmanın bir başka nedeni de verimliliktir.

Veritabanları her zaman sorgunuzu derler ve önbelleğe alır, ardından önbelleğe alınmış sorguyu yeniden kullanır (bu, sonraki istekler için açıkçası daha hızlıdır). Parametreleri kullanırsanız, farklı parametreler kullansanız bile veritabanı, parametreleri bağlamadan önce SQL dizesine göre eşleştiği için önbelleğe alınmış sorgunuzu yeniden kullanır.

Bununla birlikte, parametreleri bağlamazsanız, SQL dizesi her istekte değişir (farklı parametrelere sahiptir) ve önbelleğinizdekiyle asla eşleşmez.


2

Zaten verilen nedenlerden dolayı, parametreler çok iyi bir fikirdir. Ancak bunları kullanmaktan nefret ediyoruz çünkü parametrenin oluşturulması ve adını daha sonra bir sorguda kullanılmak üzere bir değişkene atamak, üçlü bir enkazdır.

Aşağıdaki sınıf, SQL istekleri oluşturmak için yaygın olarak kullanacağınız dizge oluşturucuyu sarmalar. Hiçbir zaman bir parametre oluşturmanıza gerek kalmadan parametreli sorgular yazmanıza olanak tanır , böylece SQL'e konsantre olabilirsiniz. Kodunuz şöyle görünecek ...

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();

Kod okunabilirliği, umarım kabul edersiniz, büyük ölçüde iyileştirilmiştir ve çıktı, uygun bir parametreleştirilmiş sorgudur.

Sınıf şuna benziyor ...

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();
        }
    }
}

1

SQL enjeksiyon sorunlarını araştırmak zorunda kaldığım çok kısa zamandan beri, 'güvenli' bir değer yaratmanın, verilerinizde gerçekten kesme işareti isteyebileceğiniz durumlara kapıyı kapattığınız anlamına geldiğini görüyorum - peki ya birinin adı , örneğin O'Reilly.

Geriye parametreler ve saklı prosedürler kalır.

Ve evet, kodu her zaman şu anda bildiğiniz en iyi şekilde uygulamaya çalışmalısınız - sadece her zaman olduğu gibi değil.


Çift kesme işareti sql sunucusu tarafından tek bir kesme işaretine çevrilecek, böylece O'Reilly, Name = 'O''Reilly'
Rune Grimstad

Öyleyse, kullanıcı verilerini görmek istediğinde kesme işaretlerini kaldırmak için karşılık gelen bir işlev var mı?
quamrana

Gerek yok. Kaçış dizisi, ayrıştırıcının dizenin sonu yerine tek bir alıntı görmesini sağlar. Ayrıştırılırken, ''gerçek olarak görür ', bu nedenle dizeniz dahili olarak karakter dizisi olarak görünecektir O'Reilly. Bu, DB'nin saklayacağı, geri alacağı, karşılaştıracağı vb. Şeydir. Kullanıcıya, siz ondan kaçtıktan sonra verilerini göstermek istiyorsanız, ön tarafta çıkış karaktersiz dizenin bir kopyasını saklayın.
cHao

1

İşte iş arkadaşlarınızı ikna etmek için faydalı bulabileceğiniz birkaç makale.

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

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

Kişisel olarak, herhangi bir dinamik kodun veritabanıma dokunmasına asla izin vermemeyi tercih ederim, bu da tüm temasların sps üzerinden olmasını gerektirir (dinamik SQl kullananlardan değil). Bu, kullanıcılara yapma izni verdiklerim dışında hiçbir şeyin yapılamayacağı ve dahili kullanıcıların (yönetici amacıyla üretim erişimine sahip çok az kişi dışında) tablolarıma doğrudan erişemeyeceği ve tahribat yaratamayacağı, veri çalamayacağı veya sahtekarlık yapamayacağı anlamına gelir. Finansal bir uygulama çalıştırıyorsanız, bu gitmenin en güvenli yoludur.


1

Kırılabilir, ancak araçlar tam sürümlere / yamalara vb. Bağlıdır.

Zaten gündeme getirilmiş olanlardan biri, istismar edilebilecek taşma / kesme hatasıdır.

Gelecekteki başka bir yol, diğer veritabanlarına benzer hatalar bulmak olabilir - örneğin MySQL / PHP yığını, değiştirme işlevini değiştirmek için belirli UTF8 dizileri kullanılabildiğinden kaçan bir sorun yaşadı - değiştirme işlevi , enjeksiyon karakterlerini tanıtmak için kandırılacaktı .

Günün sonunda, değiştirme güvenlik mekanizması beklenen ancak amaçlanan işlevselliğe dayanmaz. İşlevsellik kodun amaçlanan amacı olmadığından, keşfedilen bazı tuhaflıkların beklenen işlevselliğinizi bozma olasılığı yüksektir.

Çok sayıda eski kodunuz varsa, değiştirme yöntemi, uzun süreli yeniden yazma ve testlerden kaçınmak için geçici bir boşluk olarak kullanılabilir. Yeni kod yazıyorsanız mazeret yok.


1

Mümkün olduğunda her zaman parametreleştirilmiş sorgular kullanın. Bazen, herhangi bir tuhaf karakter kullanmadan basit bir girdi bile, veritabanındaki bir alan için bir girdi olarak tanımlanmamışsa, zaten bir SQL enjeksiyonu oluşturabilir.

Öyleyse, veritabanının girdinin kendisini tanımlama işini yapmasına izin verin, aksi takdirde kaçabilecek veya değiştirilecek garip karakterleri gerçekten eklemeniz gerektiğinde, sorun payından da tasarruf edeceğinden bahsetmiyorum bile. Hatta girdiyi hesaplamak zorunda kalmadan sonunda bazı değerli çalışma sürelerinden tasarruf edebilir.


1

Başka yanıt verenlerin 'neden bunu kendin yapmanın kötü olduğunu' ele aldığını görmedim, ancak bir SQL Kesmesi saldırısı düşünün .

Ayrıca QUOTENAMEonları parametreleri kullanmaya ikna edemezseniz yardımcı olabilecek T-SQL işlevi de vardır. Kaçan yol endişelerinin çoğunu (tümünü?) Yakalar.


1

2 yıl sonra , tekrar suçlandım ... Parametreleri zor bulan herkes VS Extension, QueryFirst'i deneyebilir . İsteğinizi gerçek bir .sql dosyasında (Doğrulama, Intellisense) düzenlersiniz. Bir parametre eklemek için, '@' ile başlayarak doğrudan SQL'inize yazmanız yeterlidir. Dosyayı kaydettiğinizde, QueryFirst sorguyu çalıştırmanıza ve sonuçlara erişmenize izin vermek için sarmalayıcı sınıfları oluşturur. Parametrenizin DB türünü arayacak ve onu, oluşturulan Execute () yöntemlerine girdi olarak bulacağınız bir .net türüne eşleyecektir. Daha basit olamazdı. Bunu doğru şekilde yapmak, başka bir şekilde yapmaktan çok daha hızlı ve kolaydır ve bir sql enjeksiyon güvenlik açığı oluşturmak imkansız hale gelir veya en azından sapıkça zorlaşır. DB'nizdeki sütunları silebilmek ve uygulamanızdaki derleme hatalarını hemen görebilmek gibi başka öldürücü avantajları da vardır.

yasal sorumluluk reddi: QueryFirst yazdım


0

Parametreli sorguları kullanmanın birkaç nedeni şunlardır:

  1. Güvenlik - Veritabanı erişim katmanı, verilerde izin verilmeyen öğelerin nasıl kaldırılacağını veya bunlardan nasıl çıkılacağını bilir.
  2. Kaygıların ayrılması - Kodum, verileri veritabanının beğeneceği bir biçime dönüştürmekle sorumlu değildir.
  3. Artıklık yok - Bu veritabanı biçimlendirmesini / çıkışını yapan her projeye bir derleme veya sınıf eklememe gerek yok; sınıf kitaplığında yerleşiktir.

0

SQL ifadesinin arabellek taşmasıyla ilgili birkaç güvenlik açığı vardı (hangi veritabanı olduğunu hatırlayamıyorum).

Söylemek istediğim şey, SQL-Injection "alıntıdan kaçmak" dan daha fazlasıdır ve bundan sonra ne olacağı hakkında hiçbir fikriniz yok.


0

Dikkate alınacak bir diğer önemli nokta da, kaçan ve kaçılmayan verileri takip etmektir. Verilerin ne zaman ham-Unicode, & -encode, biçimlendirilmiş HTML, vb. Olduğunu düzgün bir şekilde takip edemeyen tonlarca uygulama var, Web ve başka türlü. Açıktır ki, hangi dizelerin ''şifrelenip şifrelenmediğini takip etmek zor olacaktır .

Bir değişkenin tipini değiştirdiğinizde de bu bir problem - belki eskiden bir tamsayı idi, ama şimdi bir dizge. Şimdi bir sorunun var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.