PreparedStatement SQL enjeksiyonunu nasıl önler veya engeller?


122

PreparedStatements'ın SQL Injection'ı engellediğini / engellediğini biliyorum. Bunu nasıl yapıyor? PreparedStatements kullanılarak oluşturulan son form sorgusu bir dize mi olacak yoksa başka bir şekilde mi olacak?


3
Teknik olarak JDBC spesifikasyonu, SQL yerleştirme kusurlarının olmadığı konusunda ısrar etmez. Etkilenen herhangi bir sürücü bilmiyorum.
Tom Hawtin - tackline

3
@Jayesh Blog içeriklerinizi cevap olarak buraya eklemenizi öneririm. Cevapların çoğu sadece dinamik SQL sorgu oluşturma ve hazırlanan stmt farklılıkları anlatıyor. Blogunuzun yaptığı gibi, hazırlanmış ifadelerin neden daha iyi çalıştığı konusuna değinmiyorlar.
Pavan Manjunath

1
Cevap olarak eklendi, umarım yardımcı olur.
Jayesh

Yanıtlar:


78

SQL enjeksiyonunun sorunu, bir kullanıcı girdisinin SQL ifadesinin bir parçası olarak kullanılmasıdır. Hazırlanmış ifadeleri kullanarak, kullanıcı girişini bir parametrenin içeriği olarak (SQL komutunun bir parçası olarak değil) işlenmeye zorlayabilirsiniz.

Ancak, kullanıcı girişini hazırlanan ifadeniz için bir parametre olarak kullanmazsanız, bunun yerine SQL komutunuzu dizeleri birleştirerek oluşturursanız, hazırlanmış ifadeleri kullanırken bile SQL enjeksiyonlarına karşı savunmasız kalırsınız .


1
Elbette, ancak yine de parametrelerinizin bir kısmını veya tamamını kodlayabilirsiniz.
Tangens

16
Örnek lütfen - Ancak, hazırladığınız deyim için kullanıcı girdisini bir parametre olarak kullanmazsanız, bunun yerine SQL komutunuzu dizeleri birleştirerek oluşturursanız, hazırlanmış deyimleri kullanırken bile SQL enjeksiyonlarına karşı hala savunmasızsınızdır.
david blaine

4
FWIW Hazırlanmış ifadeler bir JDBC meselesi değildir - onlar bir SQL şeyidir. Hazırlanmış ifadeleri bir SQL konsolundan hazırlayabilir ve çalıştırabilirsiniz. PreparedStatement onları JDBC içinden destekler.
beldaz

198

Aynı şeyi yapmanın iki yolunu düşünün:

PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();

Veya

PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();

Kullanıcı girişinden "kullanıcı" gelmişse ve kullanıcı girişi

Robert'); DROP TABLE students; --

Sonra ilk etapta ıslatılacaksın. İkincisi, güvende olursunuz ve Küçük Bobby Tablolar okulunuza kaydolur.


8
Yani, doğru anladıysam, ikinci örnekte yürütülecek olan sorgu aslında: INSERT INTO student VALUES ("Robert '); DROP TABLE öğrenciler; -") - veya en azından bunun gibi bir şey. Bu doğru mu?
Maksimum

18
Hayır, İLK durumda, bu ifadeyi alırsınız. İkincisi, kullanıcı tablosuna "Robert"; DROP TABLE öğrencileri; - "ekler.
Paul Tomblin

3
İkinci örnekte ("güvenli" olan) Robert ' dizesini kastettiğim buydu ; DROP TABLE öğrencileri; - öğrenci tablosundaki alana kaydedilecektir. Başka bir şey mi yazdım ;)
Maks.

7
Maalesef, bu tür kafa karışıklıklarından dolayı alıntı yapmaktan kaçınmaya çalışıyorum. Bu yüzden PreparedStatements'ı parametrelerle seviyorum.
Paul Tomblin

59
Küçük Bobby Masaları. XD Büyük referans
Amalgovinus

129

PreparedStatement'ın SQL Enjeksiyonunu nasıl engellediğini anlamak için SQL Sorgusu yürütme aşamalarını anlamamız gerekir.

1. Derleme Aşaması. 2. Yürütme Aşaması.

SQL sunucu motoru bir sorgu aldığında, aşağıdaki aşamalardan geçmek zorundadır,

Sorgu Yürütme Aşamaları

  1. Ayrıştırma ve Normalleştirme Aşaması: Bu aşamada, Sorgu sözdizimi ve anlambilim açısından kontrol edilir. Sorguda kullanılan referans tablosu ve sütunlarının var olup olmadığını kontrol eder. Aynı zamanda yapacak başka görevleri de var, ancak ayrıntılara girmeyelim.

  2. Derleme Aşaması: Bu aşamada seçme, nereden, nerede vb. Sorgulamada kullanılan anahtar sözcükler makinenin anlayabileceği biçime dönüştürülür. Bu, sorgunun yorumlandığı ve karşılık gelen eyleme karar verildiği aşamadır. Aynı zamanda yapacak başka görevleri de var, ancak ayrıntılara girmeyelim.

  3. Sorgu Optimizasyon Planı: Bu aşamada, sorgunun hangi yollarla yürütülebileceğini bulmak için Karar Ağacı oluşturulur. Sorgunun çalıştırılabileceği yolların sayısını ve Sorgu yürütmenin her bir yolu ile ilişkili maliyeti bulur. Bir sorguyu yürütmek için en iyi planı seçer.

  4. Önbellek: Sorgu optimizasyon planında seçilen en iyi plan önbellekte saklanır, böylece bir dahaki sefere aynı sorgu geldiğinde, Aşama 1, Aşama 2 ve Aşama 3'ten tekrar geçmek zorunda kalmaz. Sorgu bir dahaki sefere geldiğinde, doğrudan Önbellekte kontrol edilecek ve yürütmek için oradan alınacaktır.

  5. Yürütme Aşaması: Bu aşamada, sağlanan sorgu çalıştırılır ve veriler kullanıcıya döndürülür.ResultSet nesne .

PreparedStatement API'nin yukarıdaki adımlardaki davranışı

  1. PreparedStatements eksiksiz SQL sorguları değildir ve çalışma zamanında gerçek kullanıcı tarafından sağlanan verilerle değiştirilen yer tutucular içerir.

  2. Yer tutucular içeren herhangi bir PreparedStatment SQL Server motoruna geçirildiğinde, aşağıdaki aşamalardan geçer.

    1. Ayrıştırma ve Normalleştirme Aşaması
    2. Derleme Aşaması
    3. Sorgu Optimizasyon Planı
    4. Önbellek (Yer tutucularla Derlenmiş Sorgu, Önbellekte saklanır.)

GÜNCELLEME kullanıcı set kullanıcı adı =? ve şifre =? NEREDE id =?

  1. Yukarıdaki sorgu ayrıştırılır, yer tutucularla birlikte özel işlem olarak derlenir, optimize edilir ve Önbelleğe alınır. Bu aşamada sorgu zaten derlenmiş ve makine tarafından anlaşılabilir bir biçime dönüştürülmüştür. Bu nedenle, önbellekte depolanan Sorgunun Önceden Derlenmiş olduğunu ve yalnızca yer tutucuların kullanıcı tarafından sağlanan verilerle değiştirilmesi gerektiğini söyleyebiliriz.

  2. Artık kullanıcı tarafından sağlanan veriler geldiğinde çalışma zamanında, Ön Derlenmiş Sorgu Önbellekten alınır ve yer tutucular, kullanıcı tarafından sağlanan verilerle değiştirilir.

PrepareStatementWorking

(Unutmayın, yer tutucular kullanıcı verileriyle değiştirildikten sonra, son sorgu tekrar derlenmez / yorumlanmaz ve SQL Server motoru kullanıcı verilerini, ayrıştırılması veya yeniden derlenmesi gereken bir SQL değil, saf veri olarak görür; PreparedStatement'ın güzelliği budur. )

Sorgunun tekrar derleme aşamasından geçmesi gerekmiyorsa, yer tutucularda değiştirilen veriler saf veri olarak kabul edilir ve SQL Server motoru için hiçbir anlamı yoktur ve sorguyu doğrudan yürütür.

Not: Sorgu yapısını anlayan / yorumlayan ve ona anlamlı davranışlar veren, ayrıştırma aşamasından sonraki derleme aşamasıdır. PreparedStatement durumunda, sorgu yalnızca bir kez derlenir ve önbelleğe alınmış derlenmiş sorgu, kullanıcı verilerini değiştirmek ve yürütmek için her zaman alınır.

PreparedStatement'ın tek seferlik derleme özelliği sayesinde SQL Injection saldırısı içermez.

Örnekle ayrıntılı açıklamayı burada bulabilirsiniz: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html


3
güzel açıklama
Dheeraj Joshi

4
NASIL çalıştığına dair kelimenin tam anlamıyla en eksiksiz cevap
jouell

Çok yardımcı oldu. Detaylı açıklama için teşekkürler.
Unknown

26

PreparedStatement içinde kullanılan SQL, sürücüde önceden derlenmiştir. Bu noktadan sonra, parametreler sürücüye SQL'in çalıştırılabilir bölümleri olarak değil, değişmez değerler olarak gönderilir; bu nedenle bir parametre kullanılarak hiçbir SQL enjekte edilemez. PreparedStatements'ın (ön derleme + yalnızca parametreleri gönderme) bir başka yararlı yan etkisi, sürücünün her biri SQL ayrıştırma ve derleme gerçekleştirmesi gerekmediğinden (sürücünün PreparedStatements'ı desteklediği varsayılarak) parametreler için farklı değerlerle bile birden çok kez çalıştırıldığında performans artışıdır parametrelerin değişme zamanı.


Böyle uygulanması gerekmiyor ve ben çoğu zaman öyle olmadığına inanıyorum.
Tom Hawtin - tackline

4
Aslında SQL, genellikle veritabanında önceden derlenir. Yani veri tabanı üzerinde bir yürütme planı hazırlanır. Sorguyu yürüttüğünüzde plan bu parametrelerle çalıştırılır. Ekstra fayda, aynı ifadenin, sorgu işlemcisinin her seferinde yeni bir plan derlemesi gerekmeden farklı parametrelerle yürütülebilmesidir.
beldaz

3

Ben tahmin bu bir dize olacaktır. Ancak girdi parametreleri veritabanına gönderilecek ve gerçek bir SQL ifadesi oluşturmadan önce uygun dönüştürme / dönüştürmeler uygulanacaktır.

Size bir örnek vermek gerekirse, CAST / Conversion'ın çalışıp çalışmadığını deneyebilir.
Çalışırsa, ondan nihai bir açıklama yaratabilir.

   SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))

Sayısal bir parametre kabul eden bir SQL ifadesi içeren bir örnek deneyin.
Şimdi, bir dize değişkeni (sayısal parametre olarak kabul edilebilir sayısal içerikle) iletmeyi deneyin. Herhangi bir hata yaratır mı?

Şimdi, bir dize değişkeni geçirmeyi deneyin (sayısal parametre olarak kabul edilemeyen içeriğe sahip). Ne olacağını gördün mü?


3

Hazırlanan açıklama daha güvenlidir. Bir parametreyi belirtilen türe dönüştürecektir.

Örneğin stmt.setString(1, user);,user parametreyi bir String'e .

Parametrenin çalıştırılabilir bir komut içeren bir SQL dizesi içerdiğini varsayalım : hazırlanmış bir ifade kullanmak buna izin vermez.

Buna meta karakter (aka otomatik dönüştürme) ekler.

Bu onu daha güvenli kılar.


2

SQL enjeksiyonu: kullanıcı, sql ifadesinin parçası olabilecek bir şey girme şansına sahip olduğunda

Örneğin:

Dize sorgusu = "INSERT INTO öğrenciler VALUES ('" + kullanıcı + "')"

kullanıcı "Robert" girdiğinde); DROP TABLE öğrencileri; - "girdi olarak SQL enjeksiyonuna neden olur

Hazırlanmış ifade bunu nasıl engeller?

Dize sorgusu = "INSERT INTO öğrenciler VALUES ('" + ": ad" + "')"

parameters.addValue ("ad", kullanıcı);

=> kullanıcı tekrar girdiğinde "Robert"); DROP TABLE öğrencileri; - ", girdi dizesi sürücüde değişmez değerler olarak önceden derlenmiştir ve sanırım şu şekilde dönüştürülebilir:

CAST ( 'Robert'); DROP TABLE öğrencileri; - 'AS varchar (30))

Yani sonunda, dize tablonun adı olarak kelimenin tam anlamıyla eklenecektir.

http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/


1
Yanılmıyorsam ise bölüm CAST(‘Robert’);gelen CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))kıracak, o zaman bu durumda olsaydı tablo düşmesi sürdüreceğini belirtti. Enjeksiyonu durdurur, bu yüzden örneğin senaryoyu açıklayacak kadar eksiksiz olmadığına inanıyorum.
Héctor Álvarez

1

PreparedStatement:

1) SQL ifadesinin ön derlemesi ve DB tarafında önbelleğe alınması, genel olarak daha hızlı yürütmeye ve aynı SQL ifadesini toplu işlerde yeniden kullanma becerisine yol açar.

2) Yerleşik alıntılardan ve diğer özel karakterlerden kaçarak SQL enjeksiyon saldırılarının otomatik olarak önlenmesi. Bunun, değeri ayarlamak için PreparedStatement setXxx () yöntemlerinden herhangi birini kullanmanızı gerektirdiğini unutmayın.


1

Bu yazıda açıklandığı gibi PreparedStatement, hala Dizeleri birleştiriyorsanız , tek başına size yardımcı olmaz.

Örneğin, bir haydut saldırgan hala aşağıdakileri yapabilir:

  • tüm veritabanı bağlantılarınızın meşgul olması için bir uyku işlevi çağırın, bu nedenle uygulamanızı kullanılamaz hale getirin
  • DB'den hassas verileri çıkarmak
  • kullanıcı kimlik doğrulamasını atlama

Bağlama parametrelerini kullanmıyorsanız yalnızca SQL değil, JPQL veya HQL bile tehlikeye atılabilir.

Sonuç olarak, SQL deyimleri oluştururken asla dize birleştirme kullanmamalısınız. Bu amaç için özel bir API kullanın:


1
Tek başına PreparedStatement yerine parametre bağlamanın kullanılmasının önemine işaret ettiğiniz için teşekkür ederiz. Ancak yanıtınız, SQL enjeksiyonuna karşı koruma sağlamak için özel bir API kullanmanın gerekli olduğunu ima ediyor gibi görünüyor. Durum böyle olmadığından ve PreparedStatement'ı parametre bağlamayla kullanmak da işe yaradığına göre, yeniden formüle etmek ister misiniz?
Wild Pottok

-3

Hazırlanmış İfadelerde, kullanıcı verileri parametre olarak girmeye zorlanır. Kullanıcı DROP TABLE veya SELECT * FROM USERS gibi güvenlik açığından etkilenen bazı ifadeler girerse, bunlar SQL ifadesinin parametreleri olarak kabul edileceğinden veriler etkilenmez.


Daha az kesinlikte seçilen cevapla aynı cevap.
Julien Maret
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.