SQL enjeksiyon önleme mekanizması neden parametreli hale getirilmiş sorguları kullanma yönünde gelişti?


59

Gördüğüm kadarıyla, SQL enjeksiyon saldırıları önlenebilir:

  1. Dikkatlice tarama, filtreleme, kodlama girişi (SQL'e yerleştirmeden önce)
  2. Kullanılması hazırlanmış tablolar / parametreli sorgular

Sanırım her biri için artılar ve eksiler var, ama neden 2. attı ve enjeksiyon saldırılarını engellemenin fiili bir yolu olduğu düşünüldü? Sadece daha mı güvenli ve hataya daha az yatkın mı yoksa başka faktörler var mıydı?

Anladığım kadarıyla # 1 doğru kullanılırsa ve tüm uyarılar dikkate alınırsa, # 2 kadar etkili olabilir.

Dezenfektan, Filtreleme ve Kodlama

Sanitasyon , filtreleme ve kodlamanın ne anlama geldiği arasında bazı karışıklıklar vardı . Amaçlarım için yukarıdakilerin hepsinin seçenek 1 için dikkate alınabileceğini söyleyeceğim. Bu durumda, temizlik ve filtrelemenin girdi verilerini değiştirme veya atma potansiyeline sahip olduğunu, kodlamanın olduğu gibi koruduğunu ancak kodlamadığını anladım. Enjeksiyon saldırılarını önlemek için Kaçan verilerin onu kodlamanın bir yolu olarak görülebileceğine inanıyorum.

Parametreli Sorgular ve Kodlama Kütüphanesi

Kavramları cevaplar vardır parameterized queriesve encoding librarieso birbirinin davranılır. Yanılıyorsam düzelt beni, ama farklı oldukları izlenimindeyim.

Anladığım kadarıyla, encoding librariesher zaman ne kadar iyi olursa olsun, her zaman SQL "Program" ı değiştirme potansiyeline sahipler , çünkü RDBMS'ye gönderilmeden önce SQL'de değişiklikler yapıyorlar.

Parameterized queries Öte yandan, SQL programını, sorguyu en iyi duruma getiren, sorgu yürütme planını tanımlayan, kullanılacak dizinleri vb. seçen RDBMS'ye gönderin ve ardından verileri RDBMS içindeki son adım olarak takın kendisi.

Kodlama Kütüphanesi

  data -> (encoding library)
                  |
                  v
SQL -> (SQL + encoded data) -> RDBMS (execution plan defined) -> execute statement

Parametreli Sorgu

                                               data
                                                 |
                                                 v
SQL -> RDBMS (query execution plan defined) -> data -> execute statement

Tarihsel Önemi

Bazı cevaplar, tarihsel olarak, parametreli hale getirilmiş sorguların (PQ) performans nedenleriyle ve kodlama sorunlarını hedef alan enjeksiyon saldırılarının popüler hale gelmesinden önce yaratıldığından bahseder. Bir noktada PQ'nun enjeksiyon saldırılarına karşı da oldukça etkili olduğu anlaşıldı. Sorumumun ruhuna uymak için, PQ neden tercih edilen yöntem olarak kaldı ve SQL enjeksiyon saldırılarını önleme konusunda neden diğer pek çok yöntemin üstünde gelişti?


1
Yorumlar genişletilmiş tartışmalar için değildir; bu konuşma sohbete taşındı .
maple_shaft

23
Hazırlanan ifadeler, SQL enjeksiyon saldırılarındaki evrimin bir sonucu değil . Onlar en başından beri oradaydılar. Sorunuz sahte öncüllere dayanıyor.
user207421

4
Kötü adamlardan daha zeki olduğunu düşünüyorsan # 1
paparazzo

1
“PQ neden tercih edilen yöntem olarak kaldı?” Çünkü bu en kolay ve en sağlam olanı. Ayrıca, yukarıda belirtilen performans avantajlarının PQ'lara avantajları da bulunmaktadır. Gerçekten dezavantajı yok.
Paul Draper

1
Çünkü, güvenlik bağlamında SQL enjeksiyonu konusu olmasa bile sorguların nasıl yapılacağı sorununa doğru bir çözümdür . Kaçış ve bant içi verileri komutlarla kullanma gerektiren formlar her zaman bir tasarım hatasıdır, çünkü bunlar hataya açık, sezgiseldir ve yanlış kullanıldığında kötü bir şekilde kırılırlar. Ayrıca bakınız: kabuk komut dosyası.
R. ..

Yanıtlar:


147

Sorun şu ki # 1, üzerinde çalıştığınız SQL varyantının tamamını etkin bir şekilde ayrıştırmanızı ve yorumlamanızı gerektirir, bu yüzden yapmaması gereken bir şey yapıp yapmadığını bilirsiniz. Ve veritabanınızı güncellerken bu kodu güncel tutun. Sorgularınız için girişi kabul ettiğiniz her yer . Ve batırma.

Yani evet, bu tür bir şey SQL enjeksiyon saldırılarını durduracaktı, fakat uygulanması çok daha pahalı.


60
@ dennis - Peki, SQL değişkeninizde alıntı nedir? "? '?"? U + 2018? \ U2018? İfadeleri ayırmak için püf noktaları var mı? Alt sorgularınız güncellemeler yapabilir mi? Dikkate
alınacak

7
@Dennis, her DB motorunun dizelerde kaçış karakterleri gibi şeyler yapmasının kendi yoluna sahiptir. Özellikle, bir uygulamanın birden fazla DB motoruyla çalışması veya sömürülebilecek bazı küçük sorgu sözdizimini değiştirebilecek gelecek motor sürümleriyle uyumlu olması gerekiyorsa, takılması gereken çok sayıda delik vardır.

12
Hazırlanan ifadelerin bir diğer faydası, aynı sorguyu farklı değerlerle yeniden çalıştırmanız gerektiğinde elde ettiğiniz performans kazancıdır. Ayrıca, hazırlanan ifadeler bir değerin nullbir dize veya bir sayı olarak tamamen ifade edilip edilmediğini bilmeli ve buna göre hareket etmelidir. Bu güvenlik için çok iyidir. Sorguyu bir kez çalıştırsanız bile, DB motoru zaten sizin için en iyi duruma getirilmiş olacak. Önbelleğe alınmış ise daha iyi!
Ismael Miguel,

8
@Dennis Bay Henry Null bunu doğru yaptığınız için teşekkür eder.
Mathieu Guindon

14
@Dennis ilk isim alakasız. Sorun soyadı ile ilgili. Bkz yığın taşması , Programmers.SE , Fox Sports , Kablolu , BBC , ve başka ne ;-) hızlı bir Google aramasında açabilirsiniz
Mathieu Guindon

80

Çünkü seçenek 1 bir çözüm değildir. Tarama ve filtreleme, geçersiz girişi reddetmek veya kaldırmak anlamına gelir. Ancak herhangi bir giriş geçerli olabilir. Örneğin kesme işareti "O'Malley" adında geçerli bir karakterdir. Hazırlanan ifadelerin yaptığı SQL'de kullanılmadan önce doğru bir şekilde kodlanması gerekir.


Notu ekledikten sonra, temel olarak kendi fonksiyonel olarak benzer kodunuzu sıfırdan yazmak yerine neden standart bir kütüphane işlevi kullandığınızı soruyorsunuz. Her zaman kendi kodunuzu yazmak için standart kütüphane çözümlerini tercih etmelisiniz . Daha az iş ve daha fazla bakım yapılabilir. Bu, herhangi bir işlevsellik için geçerlidir, ancak özellikle güvenliğe duyarlı bir şey için tekerleği yeniden icat etmenin kesinlikle bir anlamı yoktur.


2
İşte bu (ve diğer iki cevabın eksik kısmıydı, yani + 1). Sorunun nasıl formüle edildiğine bakıldığında, bu, kullanıcı girişini sterilize etmekle ilgili değildir , ancak şunu soruyorum : “girdiyi filtrelemek (ekleme işleminden önce)”. Eğer soru şimdi girdiyi sterilize etmekle ilgiliyse, neden kütüphanenin bunu yapmasına izin vermek yerine kendin yapardın (aynı zamanda, bu arada önbelleğe alma yürütme planlarını yapma fırsatını kaybederken)?
Arseni Mourzenko

8
@Dennis: Hijyenik veya filtreleme aracının kaldırılması bilgi. Kodlama verilerinin temsil dönüştüren demektir olmadan bilgi kaybı.
JacquesB

9
@Dennis: filtreleme, kullanıcı girişini kabul etmek veya reddetmek anlamına gelir. Örneğin, “Jeff” , “Kullanıcının yaşı” alanının girişi olarak filtrelenir , çünkü değer açıkça geçersizdir. Girdiyi filtrelemek yerine, örneğin, tekli alıntı karakterini değiştirerek, onu dönüştürmeye başlarsanız, parametreli hale getirilmiş sorguları kullandıkları veritabanı kütüphaneleriyle tamamen aynı şeyi yapıyorsunuz ; Bu durumda, sorunuz basitçe “Her projede tekerleği yeniden icat ederken neden alandaki uzmanlar tarafından yazılmış ve yazılmış bir şeyi kullanmalıyım?”
Arseni Mourzenko

3
@Dennis: O\'MalleyEğik çizgiyi, doğru ekleme için alıntıdan kaçmak için kullanıyor (en azından bazı veritabanlarında). MS SQL veya Access'te ek bir alıntı ile kaçılabilir O''Malley. Kendin yapman gerekiyorsa, çok taşınabilir değil.
AbraCadaver

5
İsmimin kaç kez düpedüz sistem tarafından reddedildiğini söyleyemem. Bazen sadece adımı kullanmamdan kaynaklanan SQL enjeksiyonundan kaynaklanan hatalar bile gördüm. Heck, bir keresinde kullanıcı adımı değiştirmem istendi çünkü ben arka uçta bir şeyleri kırıyordum.
Alexander O'Mara

60

Dize işlemi yapmaya çalışıyorsanız, gerçekten bir SQL sorgusu oluşturmazsınız. Bir SQL sorgusu üretebilecek bir dize üretiyorsunuz. Hatalar ve hatalar için çok fazla alan açan bir dolaylı yönlendirme var . Çoğu durumda, programsal olarak bir şeyle etkileşime girmekten mutlu olduğumuz düşünülürse, bu gerçekten şaşırtıcı. Örneğin, bir liste yapımız varsa ve bir öğe eklemek istiyorsak, genellikle yapmayız:

List<Integer> list = /* a list of 1, 2, 3 */
String strList = list.toString();   /* to get "[1, 2, 3]" */
strList = /* manipulate strList to become "[1, 2, 5, 3]" */
list = parseList(strList);

Birisi bunu yapmayı öneriyorsa, bunun çok saçma olduğuna ve bunun sadece şunu yapması gerektiğine doğru cevap verirsin:

List<Integer> list = /* ... */;
list.add(5, position=2);

Bu, veri yapısı ile kavramsal düzeyde etkileşime girer. Bu yapının nasıl yazdırılacağı veya ayrıştırılacağına herhangi bir bağımlılık getirmez. Bunlar tamamen dikey kararlar.

İlk yaklaşımınız ilk örnek gibidir (sadece biraz daha kötü): İstediğiniz sorgu olarak doğru şekilde ayrıştırılacak dizeyi programlı olarak oluşturabileceğini varsayıyorsunuz. Bu, ayrıştırıcıya ve çok sayıda dize işleme mantığına bağlıdır.

Hazırlanan sorguları kullanmanın ikinci yaklaşımı, ikinci numuneye çok benzer. Hazırlanmış bir sorgu kullandığınızda, esasen yasal olan ancak içinde bazı yer tutucuları olan sözde bir sorguyu ayrıştırırsınız ve daha sonra içerisindeki bazı değerleri doğru şekilde koymak için bir API kullanırsınız. Artık ayrıştırma işlemine dahil değilsiniz ve herhangi bir dize işleminden endişelenmenize gerek yok.

Genel olarak, kavramsal düzeydeki şeylerle etkileşimde bulunmak çok daha kolay ve daha az hataya meyillidir. Bir sorgu bir dize değildir, bir sorgu bir dize ayrıştırırken elde ettiğiniz ya da programlı olarak bir tane oluşturduğunuzda (ya da başka bir yöntem bir tane oluşturmanıza izin verirse).

Burada basit metin değiştirme yapan C tarzı makrolar ve rastgele kod oluşturma yapan Lisp tarzı makrolar arasında iyi bir benzetme var. C tarzı makrolarla, kaynak koddaki metni değiştirebilir ve bu, sözdizimsel hatalar veya yanıltıcı davranışlar ortaya koyabileceğiniz anlamına gelir. Lisp makrolarıyla, derleyicinin işlediği biçimde kod oluşturuyorsunuz (yani, derleyicinin işleyeceği gerçek veri yapılarını döndürüyorsunuz, okuyucunun derleyiciden önce alabileceği metinleri değil) . Lisp makrosu ile, ayrıştırma hatası olabilecek bir şey üretemezsiniz. Örneğin, (a) ab (a) oluşturamazsınız .

Lisp makrolarında bile, yine de hatalı kod oluşturabilirsiniz, çünkü orada olması gereken yapının farkında olmanız gerekmez. Örneğin, Lisp'de (let ((ab)) a) "a değişkeninin b değişkeninin değerine yeni bir sözcüksel bağlanması kurun ve sonra" a "değişkeninin değerini döndürün " ve (let (ab) a) araçlarının "a ve b değişkenlerinin yeni sözcüksel bağlarını oluşturun ve ikisini de sıfır olarak sıfırlayın ve sonra a'nın değerini döndürün." Her ikisi de sözdizimsel olarak doğrudur, ancak farklı anlamlara gelir. Bu sorunu önlemek için, anlamsal olarak daha bilinçli işlevler kullanabilir ve aşağıdaki gibi bir şey yapabilirsiniz:

Variable a = new Variable("a");
Variable b = new Variable("b");
Let let = new Let();
let.getBindings().add(new LetBinding(a,b));
let.setBody(a);
return let;

Böyle bir şeyle, sözdizimsel olarak geçersiz olan bir şeyi geri döndürmek imkansızdır ve yanlışlıkla istediğinizi değil bir şeyi geri getirmek çok zordur .


İyi açıklama!
Mike Partridge

2
Beni “iyi benzetme” de kaybettin ama önceki açıklamaya dayanarak yükseldim. :)
Wildcard

1
Mükemmel örnek! - Ve şunu da ekleyebilirsiniz: Veri türüne bağlı olarak, ayrıştırılabilir bir dize oluşturmak bazen mümkün olmayabilir veya mümkün değildir. - Parametrelerimden biri, hikaye taslağı içeren bir serbest metin alanıysa (~ 10.000 karakter)? ya da bir parametre JPG-Image ise ? - O zaman tek yol parametreleştirilmiş bir sorgu
Falco

Aslında hayır - hazırlanan açıklamaların neden sql enjeksiyonuna karşı bir savunma olarak geliştiği konusunda oldukça kötü bir açıklamadır. Özellikle verilen kod örneği, java'dadır; bu, C / C ++ teknolojisinin nerede olduğu düşünülen zaman diliminde muhtemel olarak geliştirilen sorgulanmış parametreler sorgulandığında ortaya çıkmamıştır. SQL veritabanları 1970-1980 döneminin başlarında kullanılmaya başlandı. Popüler olan yüksek seviyeli dillerden önce YOL. Heck, birçoğunun veritabanlarıyla çalışmayı kolaylaştırmaya geldiğini söyleyebilirim (PowerBuilder Kimse?)
TomTom

@TomTom aslında içeriğinizin çoğuyla aynı fikirdeyim. Burada sadece güvenlik yönüne dolaylı olarak değindim. SO'da çok sayıda SPARQL (SQL ile benzerlik içeren RDF sorgu dili) sorularına ve parametreli sorguları kullanmak yerine dizeleri bir araya getirdiklerinden çok sayıda insanın sorunlarına cevap veriyorum. Enjeksiyon saldırıları olmasa bile, parametreli hale getirilmiş sorgular, böcek / çarpmalardan kaçınmaya yardımcı olur ve böcek / çarpışmalar, enjeksiyon saldırısı olmasa bile güvenlik sorunları olabilir. Yani daha az ve daha fazlasını söyleyebilirim: parametreli hale getirilmiş sorgular iyidir, SQL enjeksiyonu bir sorun olmasa bile, ve
Joshua Taylor

21

Bu seçenek # 2 seçeneğinin genellikle en iyi yöntem olarak kabul edilmesine yardımcı olur, çünkü veritabanı sorgunun parametresiz sürümünü önbelleğe alabilir. Parametreli sorgular, SQL enjeksiyonu konusunu birkaç yıl öncesine kadar yutuyor (inanıyorum), bu yüzden iki kuşu bir taşla öldürebilirsin.


10
SQL enjeksiyonu, SQL ilk icat edildiğinden beri bir sorun olmuştur. Daha sonra sorun olmadı.
Servi

9
@ Servis Teorik olarak evet. Pratikte, yalnızca girdi mekanizmalarımız çevrimiçi olduğunda ve herkesin dövmesi için büyük bir saldırı yüzeyi sunarak gerçek bir sorun haline geldi.
Jan Doggen

8
Küçük Bobby Tables , SQL enjeksiyonundan yararlanmak için internete veya büyük bir kullanıcı tabanına ihtiyacınız olduğunu kabul etmiyor. Ve tabii ki ağlar SQL'in tarihini değiştirdiğinden , SQL ortaya çıktıktan sonra ağları beklemeniz gerekmez. Evet, güvenlik açıkları vardır az uygulamanız küçük bir kullanıcı tabanına sahip olduğunda savunmasız, ama yine de güvenlik açıklarını konum ve insanlar do veritabanı kendisi değerli veriler vardır (ve birçok zaman onları istismar çok erken veritabanı çok değerli verilerin tam olması insanlar olarak, değerli veritabanları ile teknoloji karşılayabilir) ..
Servi

5
@ Bildiğim kadarıyla, dinamik SQL nispeten geç bir özellikti; SQL'in ilk kullanımı çoğunlukla değerler için parametrelerle (hem içeri hem de dışarı) parametrelerle önceden derlendi / önceden işlendi, bu nedenle sorgulardaki parametreler yazılımdaki SQL enjeksiyonunu (belki de geçici / CLI sorgularında olmayabilir) öneriyor olabilir.
Mark Rotteveel 12:16

6
SQL enjeksiyonu konusunda bilinçli olabilirler .
user253751 13:16

20

Basitçe dedi ki: Yapmadı. İfadeniz:

SQL Injection engelleme mekanizması neden Parametreli Sorguların kullanılması yönünde gelişmiştir?

temelde kusurlu. Parametreli sorgular, SQL Injection'ın en az bilinenlerinden daha uzun bir süredir var olmuştur. Genelde LOB (Line of Business) uygulamalarında kullanılan "arama için form" işlevselliği içerisinde dize toplanmasından kaçınmanın bir yolu olarak geliştirilmiştir. Çok - MANY - yıllar sonra, birisi dize manipülasyonuyla ilgili bir güvenlik sorunu buldu.

25 yıl önce SQL yaptığımı hatırlıyorum (internet yaygın olarak kullanılmadığında - sadece başlamıştı) ve IBM DB5 IIRC sürüm 5 ile SQL arasında yaptığımı hatırlıyorum - ve bu sorguları zaten parametreleştirmişti.


Teşekkürler. Dize bitiştirilmesinden kaçınmak için neden bir ihtiyaç vardı? Bana faydalı bir özellik olacak gibi görünüyor. Biriyle bir sorunu mu var?
Dennis,

3
Aslında iki tane. İlk olarak, her zaman tamamen önemsiz değildir - neden ihtiyaç duyulmadığında neden bellek ayırma ile uğraşırsınız. Ancak ikincisi, antik çağda performans önbelleğe alma sql veritabanı tarafı tam olarak bu büyük değildi - derleme SQL pahalıydı. Bir sql hazırlanmış ifadenin (parametrelerin geldiği yer) kullanılmasının yan etkisi olarak, exeuction planları yeniden kullanılabilir. SQL Server, otomatik parametreleştirmeyi tanıttı (sorgu planlarını parametreler olmadan bile tekrar kullanmak için - bunlar düşülüyor ve ima ediliyor) Sanırım 2000 veya 2007 - arasında bir yerde, IIRC.
TomTom

2
Sorguların parametreleştirilmesi dize bitiştirme özelliğini ortadan kaldırmaz. Parametreli bir sorgu oluşturmak için dize birleştirme yapabilirsiniz. Sadece bir özelliğin kullanışlı olması, verilen bir problem için her zaman iyi bir seçim olduğu anlamına gelmez.
JimmyJames

Evet, ama dediğim gibi - onlar icat edildiğinde, dinamik SQL oldukça iyi bir performansa sahipti; 2000 ile 2007 arasında bir noktaya değindim - çok QUITE). O eski zamanda, çok kez sql çalıştırıyorsanız, gerçekten HAZIRLANMIŞ ifadeler istediniz;)
TomTom

Dinamik SQL için önbellekleme planı aslında SQL Server 7.0'a 1998'de eklendi - sqlmag.com/database-performance-tuning/…
Mike Dimmick

13

Diğer tüm iyi cevaplara ek olarak:

# 2'nin daha iyi olmasının nedeni, verilerinizi sizin kodunuzdan ayırmasıdır. # 1’de verileriniz kodunuzun bir parçasıdır ve tüm kötü şeylerin geldiği yer burasıdır. # 1 ile sorgunuzu alırsınız ve sorgunuzun verilerinizi veri olarak anladığından emin olmak için ek adımlar atmanız gerekir; oysa # 2'de kodunuzu alırsınız ve bu kod ve verileriniz veridir.


3
Ayrı kod ve veri ayrıca düşmanca kod enjeksiyonuna karşı savunmanızın veritabanı satıcısı tarafından yazılmış ve test edildiği anlamına gelir. Bu nedenle, zararsız bir sorgunun yanı sıra bir parametre olarak iletilen bir şey veritabanınızı çöpe atmak veya altüst etmekle sonuçlanırsa, veritabanı şirketinin itibarı hatta olur ve kuruluşunuz bunları dava edebilir ve kazanabilir. Ayrıca, bu kodun sömürülebilir bir hata içermesi durumunda, ihtimal sizinki yerine tüm haltların çözüldüğü bir başkasının sitesi olduğu anlamına gelir. (Sadece güvenlik onarımları ihmal etmeyin!)
nigel222

11

Parametreli sorguların, SQL enjeksiyon savunması sağlamanın yanı sıra, genellikle yalnızca bir kez derlenmenin ek bir faydası vardır, daha sonra farklı parametrelerle birden çok kez yürütülür.

SQL veri tabanı açısından select * from employees where last_name = 'Smith've select * from employees where last_name = 'Fisher'kesinlikle farklıdır ve bu nedenle ayrı ayrıştırma, derleme ve optimizasyon gerektirir. Ayrıca, derlenmiş ifadeleri saklamaya adanmış bellek alanında ayrı yuvalar tutacaktır. Ağır yüklü bir sistemde, farklı parametrelerin hesaplanması ve ek yükü olan çok sayıda benzer sorguya sahip önemli olabilir.

Daha sonra, parametreli hale getirilmiş sorguları kullanmak genellikle büyük performans avantajları sağlar.


Bence bu teori (parametreli hale getirilmiş sorgular için kullanılan hazır ifadelere dayanarak). Uygulamada, çoğu uygulama sadece bir çağrıda hazırla-bağlan-yürüteceğinden, bu nedenle çoğu zaman durumun bu olacağından şüpheliyim, bu nedenle her bir parametreli sorgu için farklı bir hazırlanmış ifade kullanın; preparedüzey, genellikle gerçek bir SQL seviyesinden oldukça farklıdır prepare).
jcaron

Aşağıdaki sorgular ayrıca SQL ayrıştırıcısından farklıdır: SELECT * FROM employees WHERE last_name IN (?, ?)ve SELECT * FROM employees WHERE last_name IN (?, ?, ?, ?, ?, ?).
Damian Yerrick 14:16

Evet, sahipler. Bu yüzden MS 1998’de tekrar SQL Server 7’ye önbellekleme sorgu planı ekledi. Olarak: Bilgileriniz eskidir.
TomTom

1
@TomTom - sorgu planı önbelleğe alma, ipucu gibi göründüğünüz otomatik parametreleştirmeyle aynı değildir. Olduğu gibi, göndermeden önce okuyun.
mustaccio

@ mustaccio Aslında en azından MS ikisi aynı anda tanıttı.
TomTom

5

Bekle ama neden?

Seçenek 1, her tür giriş için sterilize etme rutinleri yazmanız gerektiği anlamına gelirken, seçenek 2 daha az hataya eğilimlidir ve yazmanız / test etmeniz / sürdürmeniz için daha az koddur.

Neredeyse kesinlikle "tüm uyarılarla ilgilenmek" , düşündüğünüzden daha karmaşık olabilir ve diliniz (örneğin, Java Hazırlık Bildirimi), düşündüğünüzden daha fazla şey ifade eder.

Hazırlanan ifadeler veya parametreleştirilmiş sorgular, veritabanı sunucusunda önceden derlenir, böylece parametreler ayarlandığında, sorgu artık bir SQL dizesi olmadığından SQL birleştirme işlemi gerçekleştirilmez. Ek bir avantaj, RDBMS'nin sorguyu önbelleğe alması ve sonraki çağrılar, parametre değerleri değişse bile aynı SQL olarak kabul edilirken, birleştirilmiş SQL ile her sorgu farklı değerlerle çalıştırıldığında sorgunun farklı olması ve RDBMS'nin ayrıştırması gerekmesidir. , yürütme planını tekrar oluşturun, vb.


1
JDBC anitlemeyi dezenfekte etmeyin. Protokol parametresi için özel bir bölüme sahiptir ve DB sadece bu parametreleri yorumlamaz. Bu nedenle tablo adını parametreden ayarlayabilirsiniz.
talex

1
Neden? Parametre ayrıştırılmazsa veya yorumlanmazsa, bir şeyden kaçmak için bir sebep yoktur.
talex

11
Parametreli bir sorgunun nasıl çalıştığının yanlış bir görüntüsünün olduğunu düşünüyorum. Bu sadece daha sonra ikame edilen parametrelerin bir durumu değildir , asla ikame edilmez . Bir DBMS, herhangi bir sorguyu bir "plan" a çevirir, sonucunuzu almak için gerçekleştirileceği bir dizi adım; parametreli hale getirilmiş bir sorguda, bu plan bir fonksiyon gibidir: yürütüldüğünde tedarik edilmesi gereken çeşitli değişkenleri vardır. Değişkenler sağlandığı zaman, SQL string tamamen unutuldu ve plan sadece verilen değerlerle gerçekleştirildi.
IMSoP

2
@IMSoP Bu benim bir yanılgı oldu. Her ne kadar SO'nun bu soruya verilen en çok oy alan iki cevabında görebileceğiniz gibi ortak bir soru olduğunu düşünüyorum rağmen stackoverflow.com/questions/3271249/… . Ben okudum ve haklısın. Cevabı değiştirdim.
Tulains Córdova

3
@TomTom Performans için harika , ancak güvenlik için hiçbir şey yapmaz . Ele geçirilmiş bir dinamik SQL parçası derlenip önbelleklendiğinde, program çoktan değiştirildi . Dinamik olmayan parametreleştirilmiş SQL'den bir plan oluşturmak ve daha sonra veri elemanlarını iletmek, temelde kendisine tam SQL dizeleri olarak sunulan iki sorgu arasındaki benzerliği soyutlayan bir DBMS'den farklıdır.
IMSoP,

1

İdeal bir "sterilize et, filtrele ve kodla" yaklaşımının nasıl olacağını düşünelim.

Dezenfekte etmek ve filtrelemek, belirli bir uygulama bağlamında anlam ifade edebilir, ancak sonuçta ikisi de "bu verileri veritabanına koyamazsınız" demekten vazgeçer. Uygulamanız için bu iyi bir fikir olabilir, ancak genel bir çözüm olarak önerebileceğiniz bir şey değildir, çünkü veritabanında rasgele karakterler depolayabilmesi gereken uygulamalar olacaktır.

Böylece kodlama kalıyor. Kaçış karakterleri ekleyerek dizeleri kodlayan bir işleve sahip olarak başlayabilirsiniz, böylece bunları kendi başınıza değiştirebilirsiniz. Farklı veritabanları kaçan farklı karakterlere ihtiyaç duyduğundan (bazı veritabanlarında, her ikisi de \'ve ''her ikisi için de geçerli kaçış dizileri vardır ', ancak diğerleri için değil), bu işlevin veritabanı satıcısı tarafından sağlanması gerekir.

Ancak tüm değişkenler dizge değildir. Bazen bir tamsayı veya tarih yerine geçmeniz gerekir. Bunlar, dizelere farklı şekilde temsil edilir, bu nedenle farklı kodlama yöntemlerine ihtiyacınız vardır (yine, bunların veritabanı satıcısına özgü olması gerekir) ve bunları sorguya farklı şekillerde yerleştirmeniz gerekir.

Bu nedenle, belki de veritabanı sizin için ikame işlemeyi ele alırsa işler daha kolay olacaktır - sorgunun ne tür bir beklenti beklediğini ve verilerin güvenli bir şekilde nasıl kodlanacağını ve sorgunuzu güvenli bir şekilde nasıl sorgulayacağınızı zaten biliyor, bu yüzden endişelenmenize gerek yok kodunda.

Bu noktada, sadece parametreli hale getirilmiş sorguları yeniden icat ettik.

Sorgular parametrelendirildikten sonra, performans optimizasyonları ve basitleştirilmiş izleme gibi yeni fırsatlar açar.

Kodlamanın doğru yapılması zordur ve kodlama-tamam-sağ parametreleme işleminden ayırt edilemez.

Eğer gerçekten bina sorguları bir yolu olarak dize enterpolasyon gibi, geçmeli dize interpolasyon sahip dillerinde (Scala ve ES2015 akla gelen) bir çift vardır, öyleyse orada olan kütüphaneler , sen dize enterpolasyon gibi bakmak Parametrelenmiş sorguları yazalım ama SQL enjeksiyonundan güvenli - yani ES2015 sözdiziminde:

import {sql} from 'cool-sql-library'

let result = sql`select *
    from users
    where user_id = ${user_id}
      and password_hash = ${password_hash}`.execute()

console.log(result)

1
"Kodlamanın doğru yapılması zor" - hahaha. O değil. Bir veya iki gün, hepsi belgelenmiştir. Yıllar önce bir ORM için bir kodlayıcı yazdım (çünkü sql sunucusunun parametreleri sınırlaması vardır ve bu nedenle bir ifadeye 5000-10000 satır eklemek sorunludur (15 yıl önce) büyük bir sorun olduğunu hatırlamıyorum.
TomTom

1
Belki de SQL Server problemsiz olduğu için yeterince düzenli, ancak diğer DB'lerde sorunla karşılaştım - eşleşmeyen karakter kodlamaları olan köşe durumlarda, belirsiz yapılandırma seçenekleri, yerel ayar tarih ve sayı sorunları. Bunların hepsi çözülebilir, ancak DB'nin tuhaflıkları hakkında en azından bir el yazısı bilgisine ihtiyaç duyuyor (Sana bakıyorum, MySQL ve Oracle).
James_pic

3
@ TomTom Kodlama, zaman içinde çarpan yaptığınız andan itibaren elde etmek çok zordur. DB satıcınız bir sonraki sürümde yeni bir yorum stili oluşturmaya karar verdiğinde veya bir korkak bir yükseltme işleminde yeni bir anahtar kelime olduğunda ne yaparsınız? Teorik olarak RDBMS'nizin bir sürümünde doğru olarak kodlama yapabilir ve bir sonraki revizyonda yanlış olabilirsiniz. Satıcıları standart dışı sözdizimini kullanarak koşullu yorumlara
Eric

@Eric, bu açıkça korkunç. (Postgres kullanıyorum; eğer onlarla karşılaşmak için henüz tuhaf bir siğile sahipse.)
Wildcard

0

Seçenek 1'de, çok büyük bir çıktı boyutuyla eşlemeye çalıştığınız, size = infinity büyüklüğünde bir girdi kümesiyle çalışıyorsunuz. Seçenek 2'de, girişinizi seçtiğiniz her şeye sınırladınız. Başka bir deyişle:

  1. [ Tüm güvenli SQL sorguları ] için [ sonsuzluk ] 'u dikkatlice inceleyin ve filtreleyin
  2. [ Kapsamınızla sınırlı önceden düşünülmüş senaryolar ] kullanma

Diğer cevaplara göre, kapsamınızı sonsuzluktan uzaklaştırmanın ve yönetilebilir bir şeye doğru bazı performans avantajları olduğu da görülüyor.


0

Yararlı SQL modellerinden biri (özellikle modern lehçeler), her SQL deyiminin veya sorgunun bir program olduğudur. Yerel bir ikili çalıştırılabilir programda, en tehlikeli tür güvenlik açıkları bir saldırganın program kodunun üzerine farklı talimatlarla yazabileceği veya üzerinde değişiklik yapabileceği taşmalardır.

Bir SQL enjeksiyon güvenlik açığı, C gibi bir dilde bir arabellek taşması izomorfiktir. History, arabellek taşmalarının önlenmesinin çok zor olduğunu göstermiştir - açık incelemeye tabi son derece kritik kodlar bile bu güvenlik açıklarını içermektedir.

Taşma güvenlik açıklarını gidermeye yönelik modern yaklaşımın önemli bir yönü, belleğin belirli bölümlerini çalıştırılamaz olarak işaretlemek ve diğer belleğin salt okunur olarak işaretlenmesi için donanım ve işletim sistemi mekanizmalarının kullanılmasıdır. ( Örneğin Yürütülebilir alan koruması hakkındaki Wikipedia makalesine bakın .) Bu şekilde, bir saldırgan verileri değiştirebilse bile, saldırgan enjekte edilen verilerinin kod olarak değerlendirilmesine neden olamaz.

Öyleyse, bir SQL enjeksiyon güvenlik açığı bir arabellek taşmasına eşdeğerse, SQL NX bitine veya salt okunur bellek sayfalarına eşdeğerdir? Cevap şudur: parametreli hale getirilmiş sorgular ve sorgu olmayan istekler için benzer mekanizmalar içeren hazır ifadeler . Hazırlanan ifade, salt okunur olarak işaretlenmiş belirli bölümlerle derlenir, bu nedenle bir saldırgan programın bu bölümlerini ve çalıştırılabilir veri olarak işaretlenen diğer bölümleri (hazırlanan ifadenin parametreleri) değiştiremez; hiçbir zaman program kodu olarak değerlendirilmez, bu nedenle kötüye kullanım potansiyelinin çoğunu ortadan kaldırır.

Elbette, kullanıcı girişini dezenfekte etmek iyidir, ancak gerçekten güvenli olması için paranoyak olmanız gerekir (veya aynı zamanda bir saldırgan gibi düşünmek için). Program metni dışındaki bir kontrol yüzeyi bunu yapmanın yoludur ve hazırlanan ifadeler SQL için bu kontrol yüzeyini sağlar. Bu nedenle, hazırlanan ifadelerin ve dolayısıyla parametreleştirilmiş sorguların, güvenlik uzmanlarının büyük çoğunluğunun önerdiği yaklaşım olduğu şaşırtıcı değildir.


Bunların hepsi güzel ve zekâlı, ancak başlığa göre soruyu ele almıyor.
TomTom

1
@TomTom: Ne demek istiyorsun? Soru tam olarak neden parametreli sorguların SQL enjeksiyonunu önlemek için tercih edilen mekanizma olduğu ile ilgilidir; Cevabım, parametreli hale getirilmiş sorguların neden kullanıcı girişini temizlemekten daha güvenli ve sağlam olduğunu açıklıyor.
Daniel Pryden

Üzgünüm ama MY soru "Neden SQL Injection engelleme mekanizması Parametreli Sorguları kullanma yönüne dönüştü?" Yapmadılar. Şimdilik değil, tarihle ilgili.
TomTom

0

Bu konuda buraya yazmayı reddettim: https://stackoverflow.com/questions/6786034/can-parameterized-statement-stop-all-sql-injection/33033576#33033576

Ancak, sadece basit tutmak için:

Parametreli sorguların çalışma şekli, sqlQuery'nin bir sorgu olarak gönderilmesi ve veritabanı bu sorgunun ne yapacağını tam olarak bilmesi ve ancak bundan sonra kullanıcı adını ve parolaları yalnızca değerler olarak ekleyebilmesidir. Bu, sorguyu etkileyemedikleri anlamına gelir, çünkü veritabanı zaten sorgunun ne yapacağını bilir. Bu durumda, bu durumda "Nobody OR 1 = 1 '-" kullanıcı adını ve yanlış çıkması gereken boş bir şifre arayacaktır.

Yine de bu tam bir çözüm değildir ve giriş doğrulama işleminin yine de yapılması gerekecektir, çünkü bu, XSS saldırıları gibi diğer sorunları da yine de javascript'i veritabanına koyabileceğiniz gibi etkilemeyecektir. Sonra bu bir sayfaya okunursa, herhangi bir çıktı doğrulamasına bağlı olarak normal javascript olarak görüntüler. Bu yüzden gerçekten yapılacak en iyi şey hala giriş doğrulama kullanmak, ancak herhangi bir SQL saldırısını durdurmak için parametreli hale getirilmiş sorgular veya saklı yordamlar kullanmak.


0

Hiç SQL kullanmadım. Fakat belli ki insanların sahip olduğu sorunların ne olduğunu duyuyorsunuz ve SQL geliştiricileri bu "SQL Injection" ile ilgili problemler yaşadılar. Uzun zamandır çözemedim. Ardından, SQL ifadeleri yaratan insanların, gerçek metinsel SQL kaynak ifadeleri, bazılarını bir kullanıcı tarafından girilen dizeleri birleştirerek fark ettim. Ve bu gerçekleşmeyle ilgili ilk düşüncem şok oldu. Toplam şok. Düşündüm: Birisi nasıl bu kadar saçma aptal olabilir ve böyle bir programlama dilinde nasıl ifade verebilir? Bir C veya C ++ veya Java veya Swift geliştiricisi için bu tamamen delilik.

Bununla birlikte, bir C stringini argüman olarak alan bir C fonksiyonunu yazmak çok zor değildir ve aynı dizeyi temsil eden C kaynak kodundaki bir string değişmezine benzeyen farklı bir dize üretir. Örneğin, bu işlev abc'yi "abc" ve "abc" - "\" abc \ "" ve "\" abc \ "" - "\" \\ "abc \\" \ "" olarak çevirir. (Peki, bu size yanlış görünüyorsa, html. Bunu yazdığımda doğru, ancak görüntülendiğinde doğru değildi) Ve bir kez C işlevi yazıldığında, C kaynak kodunu oluşturmak hiç de zor değil. kullanıcı tarafından sağlanan bir giriş alanından gelen metin bir C string değişmezine dönüştürülür. Güvenli olması zor değil. Neden SQL geliştiricileri bu yaklaşımı SQL enjeksiyonlarından kaçınmanın bir yolu olarak kullanmayacaklardı.

"Sanitizing" tamamen kusurlu bir yaklaşımdır. Ölümcül kusur, belirli kullanıcı girişlerini yasa dışı kılmasıdır. Genel bir metin alanının benzeri metin içeremediği bir veritabanı ile bitiyorsunuz; Tablo ya da zarar vermek için bir SQL enjeksiyonunda ne kullanırsanız kullanın. Bunu kabul edilemez buluyorum. Bir veritabanı metin depolarsa, herhangi bir metni depolayabilmelidir . Ve pratik kusur şu ki, sterilizatör onu doğru anlayamıyor gibi görünüyor :-(

Elbette, parametreli hale getirilmiş sorgular, derlenmiş bir dili kullanan herhangi bir programcının beklediği şeydir. Hayatı çok daha kolay hale getirir: Bazı string girdileriniz vardır ve onu bir SQL string'e çevirmek için bile zahmete girmezsiniz, ancak sadece bir string olarak herhangi bir karaktere zarar verme olasılığı olmadan parametre olarak iletin.

Bu nedenle, derlenmiş dilleri kullanan bir geliştiricinin bakış açısından, temizlik, benim için asla gerçekleşmeyecek bir şeydir. Dezenfekte etme ihtiyacı delilik. Parametreli sorgular, sorunun net çözümüdır.

(Josip'in cevabını ilginç buldum. Temelde parametreleştirilmiş sorgularla SQL'e yönelik herhangi bir saldırıyı durdurabileceğinizi ancak veritabanında JavaScript enjeksiyonu oluşturmak için kullanılan bir metnin olabileceğini söylüyor :-( Yine aynı problemi yaşıyoruz) ve Javascript'in bunun için bir çözümü olup olmadığını bilmiyorum.


-2

Asıl sorun, bilgisayar korsanlarının sağlık koşullarını çevrelemenin yollarını bulmasıdır; parametrelenmiş sorgular performans ve belleğin ekstra faydaları ile mükemmel şekilde çalışan mevcut bir prosedürdü.

Bazı insanlar sorunu "sadece tek bir alıntı ve çift alıntı" olarak basitleştirir, ancak bilgisayar korsanları farklı kodlamalar kullanmak veya veritabanı işlevlerini kullanmak gibi algılamayı engellemenin akıllı yollarını buldular.

Her neyse, yıkıcı bir veri ihlali oluşturmak için yalnızca tek bir dizgiyi unutmanız gerekiyordu. Bir veritabanı veya sorguyla veritabanının tamamını indirmek için komut dosyalarını otomatik hale getirebilen bilgisayar korsanları. Yazılım açık kaynak kodlu bir paket veya ünlü bir işletme paketi gibi iyi biliniyorsa, kullanıcılar ve şifreler tablosunu kolayca kullanabilirsiniz.

Öte yandan, yalnızca birleştirilmiş sorguları kullanmak sadece kullanmayı öğrenme ve ona alışma sorunuydu.

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.