Saklı prosedürler SQL enjeksiyonunu önlüyor mu?


83

Depolanan prosedürlerin PostgreSQL veritabanlarına SQL enjeksiyon saldırılarını önlediği doğru mu? Biraz araştırma yaptım ve yalnızca saklı yordamlar kullanıyor olsak bile SQL Server, Oracle ve MySQL'in SQL enjeksiyonuna karşı güvenli olmadığını öğrendim. Ancak, bu sorun PostgreSQL'de mevcut değildir.

PostgreSQL çekirdeğindeki saklı yordam uygulaması, SQL enjeksiyon saldırılarını engelliyor mu, yoksa başka bir şey mi? Yoksa PostgreSQL, yalnızca saklı yordamlar kullansak bile, SQL enjeksiyonuna karşı duyarlı mıdır? Öyleyse, lütfen bana bir örnek göster (örn. Kitap, site, kağıt vb.).


4
İşin garibi, buradaki en iyi yanıtlar çoğunlukla, soru Postgres ile ilgili iken, SQL Server ile ilgilenen OT . İşte Postgres için ilgili bir cevap: dba.stackexchange.com/questions/49699/… . Birkaç kişi daha var, aramayı deneyin: dba.stackexchange.com/…
Erwin Brandstetter

@ErwinBrandstetter, asıl soru postgreslerle (OP tarafından) etiketlenmedi ve diğer birkaç DBMS'den de bahsetti. Sanırım bu, diğer DBMS'ye odaklanan çeşitli cevapların nedeni. Postgres'e odaklanmış bir tane daha eklemenizi öneririm.
ypercubeᵀᴹ

@ ypercubeᵀᴹ: Zaman bulduğumda buraya bir cevap ekleyeceğim. Bu arada dba.stackexchange.com/questions/49699/… adresini daha net ve kapsamlı bir şekilde güncelledim .
Erwin Brandstetter

Yanıtlar:


71

Hayır, saklı yordamlar SQL enjeksiyonunu engellemez. İşte maalesef SQL enjeksiyonuna izin veren saklı bir prosedürün gerçek bir örneği (kurumda çalıştığım yerde çalıştığım birisi).

Bu sql sunucusu kodu:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

postgres kabaca eşdeğer:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

Geliştiricinin fikri çok yönlü bir arama prosedürü oluşturmaktı, ancak sonuç WHERE yan tümcesinin küçük Bobby Tables'tan ziyarete izin veren kullanıcının istediği her şeyi içerebilmesiydi .

SQL ifadeleri veya saklı yordam kullanıp kullanmamanız önemli değil. Önemli olan, SQL'inizin parametreleri veya birleştirilmiş dizeleri kullanmasıdır. Parametreler SQL enjeksiyonunu önler; birleştirilmiş dizeler SQL enjeksiyonuna izin verir.


46

SQL-Injection saldırıları, güvenilir olmayan girişin doğrudan sorgulara eklendiği, kullanıcının bu kanonik XKCD çizgi romanında gösterildiği gibi rasgele kod yürütmesine izin veren saldırılardır .

Böylece durumu anlıyoruz:

userInput = getFromHTML # "Robert ') Bırakma tablosu öğrencileri; -"

Query = "StudentName =" + userInput olan öğrencilerden * seçin

Saklı Prosedürler, genel olarak, SQL parametreleri saldırılarına karşı iyi savunmadır, çünkü gelen parametreler asla ayrıştırılmaz.

Saklı yordamda, çoğu DB'de (ve programlarda, önceden derlenmiş sorguların saklı yordamlar olarak sayıldığını unutmayın) aşağıdakine benzer:

 

Stored procdure foo oluşturun (
studentName = 'in olduğu öğrencilerden * seçin
);

Ardından, program erişim istediğinde, çağrı yapar foo(userInput)ve sonucu mutlu bir şekilde alır.

Saklı yordam, insanlar kötü saklı yordamlar yazabildiğinden, SQL-Injection'a karşı sihirli bir savunma değildir . Ancak, önceden derlenmiş sorguları, veritabanında veya programda depolansınlar, SQL-Injection'ın nasıl çalıştığını anlarsanız, güvenlik açıklarını açmak çok daha zordur .

SQL-Injection hakkında daha fazla bilgi edinebilirsiniz:


29

Evet, bir dereceye kadar.
Yalnızca Saklı Prosedürler, SQL Injection'ı engellemez.

OWASP’den SQL Injection hakkında ilk alıntı yapalım

Bir SQL enjeksiyon saldırısı, istemciden uygulamaya veri girişi yoluyla bir SQL sorgusunun eklenmesinden veya "enjeksiyonundan" oluşur. Başarılı bir SQL Injection kullanımı, veritabanındaki hassas verileri okuyabilir, veritabanı verilerini değiştirebilir (Ekle / Güncelle / Sil), veritabanında yönetim işlemlerini yürütebilir (DBMS'yi kapatma gibi), DBMS dosyasında bulunan belirli bir dosyanın içeriğini kurtarabilir sistemi ve bazı durumlarda işletim sistemine komutlar verin. SQL enjeksiyon saldırıları, önceden tanımlanmış SQL komutlarının yürütülmesini sağlamak için SQL komutlarının veri düzlemi girişine enjekte edildiği bir enjeksiyon saldırısı türüdür.

Saklı yordam kullanıyor olsanız bile, kullanıcı girişlerini dezenfekte etmeniz ve SQL ifadelerini birleştirmeniz gerekmez.

Jeff Attwood "içinde sql birleştirerek sonuçlarını açıkladı bana parametreli SQL ver, ya da ölüm "

Aşağıda, SQL Injection'ı her duyduğumda aklıma gelen ilginç çizgi film alt metin olduğunu düşünüyorum.

Göz at SQL Enjeksiyon Önleme Cheat Sheet , korunma yöntemleri düzgünce açıklanmıştır ...


12

Dize bitiştirme, SQL Injection'ın nedenidir. Bu, parametreleştirme kullanılarak önlenir.

Saklı yordamlar, birleştirdiğinizde geçersiz sözdizimini zorlayarak ek bir güvenlik katmanı ekler ancak bunlarda dinamik SQL kullanırsanız "güvenli" değildir.

Bu nedenle, yukarıdaki kodunuz bu dizelerin birleştirilmesinden kaynaklanıyor

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

Bu neyse ki , geçersiz sözdizimi verir

Parametre verecek

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

Bu şu anlama gelir

  • @UserName = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = monkey

Şimdi, yukarıdaki kodda hiçbir satır alamayacaksınız, çünkü kullanıcının olmadığını sanıyorum x' AND 1=(SELECT COUNT(*) FROM Client); --

Saklanan proc bu şekilde görünüyorsa (birleştirilmiş dinamik SQL kullanarak ), parametrik depolanmış proc çağrınız yine de SQL Injection'a izin verecek

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

Böylece, gösterildiği gibi, dizgi birleştirme SQL enjeksiyonu için ana düşmandır

Saklı yordamlar kapsülleme, işlem işleme, azaltılmış izinler vb. Ekler, ancak yine de SQL enjeksiyonu için kötüye kullanılabilir.

Parametreleme hakkında daha fazla bilgi için Yığın Taşması üzerine bakabilirsiniz


10

"SQL enjeksiyon saldırıları zaman ne kullanıcı girişi yanlış kodlanmış. Kullanıcı, sorgusu ile gönderdiği bazı veriler, yani değerler Genellikle, kullanıcı girişi olan $_GET, $_POST, $_COOKIE, $_REQUEST, veya $_SERVERdiziler. Ancak, kullanıcı girişi aynı zamanda diğer çeşitli gelebilir kaynakları, vb prizleri, uzaktan web siteleri, dosyalar, gibi .. Bu nedenle, gerçekten gereken sabitler ama her şeyi tedavi (gibi 'foobar') kullanıcı girişi olarak ."

Bu konuyu son zamanlarda iyice araştırdım ve bu konuyu herkes için daha eksiksiz ve öğretici hale getirerek oldukça ilginç materyallerle paylaşmak istiyorum.



YouTube'dan


Vikipedi'den


OWASP'tan


PHP Kılavuzundan


Microsoft ve Oracle’dan


Yığın Taşması


SQL enjeksiyon tarayıcı


2

Saklı prosedürler sihirli bir şekilde SQL enjeksiyonunu engellemez, ancak çok daha kolay bir şekilde önlenmesini sağlar. Tek yapmanız gereken, aşağıdakine benzer bir şey (Postgres örneği):

CREATE OR REPLACE FUNCTION my_func (
  IN in_user_id INT 
)
[snip]
  SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]

Bu kadar! Sorun yalnızca dize birleştirme (yani dinamik SQL) aracılığıyla bir sorgu oluştururken ortaya çıkar ve hatta bu durumlarda bile bağlayabilirsiniz! (Veritabanına göre değişir.)

Dinamik sorguda SQL enjeksiyonunu nasıl önleyebilirim:

Adım 1) Dinamik bir sorguya gerçekten ihtiyacınız olup olmadığını kendinize sorun. Yalnızca girişi ayarlamak için dizeleri birbirine yapıştırıyorsanız, muhtemelen yanlış yapıyorsunuz demektir. (Bu kuralın istisnaları vardır - bunun bir istisnası, bazı veritabanlarındaki sorguları bildirmektir, her yürütme için yeni bir sorgu derlemeye zorlamazsanız performans sorunlarınız olabilir. Ancak bu konuyu araştırmadan önce araştırın. )

Adım 2) RDBMS'niz için değişkeni ayarlamanın uygun yolunu araştırın. Örneğin Oracle şunları yapmanıza izin verir (dokümanlarından alıntı yaparak):

sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE ' 
           || v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!

Burada hala girişi birleştirmiyorsunuz. Güvenle bağladınız! Yaşasın!

Veritabanınız yukarıdaki gibi bir şeyi desteklemiyorsa (umarım hiçbiri hala bu kadar kötü değildir, ancak şaşırmam) - ya da girişinizi gerçekten birleştirmek zorundaysanız ("bazen" durumundaki bildirimleri sorguladığınız gibi) Ben yukarıyı ima ettim), o zaman uygun bir kaçış işlevi kullanmalısınız. Kendin yazma. Örneğin postgres quote_literal () işlevini sağlar. Yani kaçardın:

sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);

Bu, eğer in_name '[snip] veya 1 = 1' ("veya 1 = 1" bölümü gibi) bir şey ise, kullanıcının tüm satırları seçerek kullanıcının yapmaması gereken maaşları görmesini sağlar!), Sonra quote_literal sizin poponuzu kaydeder sonuç dizesini yapmak:

SELECT salary FROM employees WHERE name = '[snip] or 1=1'

Hiçbir sonuç bulunmayacak (gerçekten garip isimleri olan bazı çalışanlarınız yoksa).

Bunun özü bu! Şimdi, sizi eve götürmek için SQL Injection konusunda Oracle guru Tom Kyte'nin klasik bir yazısına bağlantı vermeme izin verin : Linky


quote_ident()Söz etmeyi unutmayın - fakat genel olarak enjeksiyonlara dayanıklı dinamik SQL yazmanın en kolay yolu tanımlayıcılar ve değişmezler için format()yer tutucuları kullanmak ve kullanmaktır . Bu yolla SQL, eşdeğer versiyonundan ve fonksiyonlarından çok daha okunaklıdır%I%L||quote_....()
a_horse_with_no_name 25:18
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.