it-swarm-tr.com

Hazırlanan ifadeler SQL enjeksiyonuna karşı% 100 güvenli midir?

Hazırlanan ifadeler aslında Kullanıcı tarafından sağlanan tüm parametrelerin sorguya bağlı parametreler olarak geçtiği varsayılarak SQL enjeksiyonuna karşı% 100 güvenli midir?

Ne zaman eski mysql_ StackOverflow fonksiyonları (ne yazık ki, çok sık), genellikle insanlara hazırlanan ifadelerin SQL enjeksiyon güvenlik önlemlerinin Chuck Norris (veya Jon Skeet) olduğunu söylüyorum.

Ancak, kategorik olarak "bu% 100 güvenlidir" bildiren hiçbir belge görmedim. Onları anladım, sorgu dilini ve parametrelerini sunucunun ön kapısına kadar ayırıyorlar, bu da onları ayrı varlıklar olarak ele alıyor.

Bu varsayımda doğru muyum?

80
Polynomial

SQL enjeksiyonundan% 100 güvenli garanti? (Benden) almayacaksın.

Prensip olarak, veritabanınız (veya kendi dilinizde db ile etkileşime giren kütüphane), bir dizi gelişmiş saldırıya açık, güvenli bir şekilde bağlı parametrelerle hazırlanmış ifadeleri kullanabilir, örneğin arabellek taşmalarından yararlanma veya kullanıcıda boş sonlandırma karakterleri kullanma (Bu tür saldırıların temelde farklı oldukları için SQL enjeksiyonu olarak adlandırılmaması gerektiğini iddia edebilirsiniz; ancak bu sadece anlambilimdir).

Alanda gerçek veritabanları üzerinde hazırlanan ifadelere yapılan bu saldırıların hiçbirini duymadım ve SQL enjeksiyonunu önlemek için bağlı parametreleri kullanmanızı şiddetle tavsiye ediyorum. Bağlı parametreler veya giriş sanitasyonu olmadan, SQL enjeksiyonu yapmak önemsizdir. Sadece giriş sanitasyonu ile, sanitasyon etrafında belirsiz bir boşluk bulmak oldukça sık mümkündür.

Bağlı parametrelerle, SQL sorgusu yürütme planınız, SQL girişini mümkün kılmak zorunda olmayan kullanıcı girişine dayanmadan önceden hesaplanır (eklenen tırnaklar, yorum sembolleri vb. Yalnızca derlenmiş SQL deyimine eklenir).

Hazırlanan ifadeleri kullanmaya karşı tek argüman, veritabanınızın gerçek sorguya bağlı olarak yürütme planlarınızı optimize etmesini istemenizdir. Tam sorgu verildiğinde veritabanlarının çoğu, en uygun yürütme planını yapacak kadar akıllıdır; örneğin, sorgu tablonun büyük bir yüzdesini döndürürse, eşleşmeleri bulmak için tüm tablonun içinden geçmek ister; eğer sadece birkaç kayıt alacaksa indeks tabanlı bir arama yapabilirsiniz [1] .

DÜZENLEME: İki eleştiriye yanıt vermek (yorumlar için biraz fazla uzun):

Birincisi, diğerlerinin de belirttiği gibi, hazırlanmış ifadeleri ve bağlı parametreleri destekleyen her ilişkisel veritabanı, bağlı parametrelerin değerine bakmadan hazırlanan ifadeyi önceden derlemez. Birçok veritabanı bunu normal olarak yapar, ancak veritabanlarının yürütme planını hesaplarken bağlı parametrelerin değerlerine bakması da mümkündür. Ayrılmış bağlı parametrelerle hazırlanan ifadenin yapısı, veritabanının SQL ifadesini (SQL anahtar sözcükleri dahil) bağlı parametrelerdeki verilerden (bağlı parametrede hiçbir şeyin olmayacağı) temiz bir şekilde ayırt etmesini kolaylaştırdığından, bu bir sorun değildir. SQL anahtar kelimesi olarak yorumlanır). Değişkenlerin ve SQL anahtar sözcüklerinin birbirine karışacağı dize birleştirme işleminden SQL ifadeleri oluşturulurken bu mümkün değildir.

İkincisi, diğer cevap belirttiği gibi, bir programda bir noktada bir SQL ifadesi çağırırken bağlı parametreleri kullanmak, bu üst düzey çağrı yaparken SQL enjeksiyonunu güvenli bir şekilde önleyecektir. Ancak, uygulamanın başka bir yerinde SQL enjeksiyon güvenlik açıklarınız varsa (ör. Veritabanınızda sakladığınız ve çalıştırdığınız kullanıcı tarafından tanımlanmış işlevlerde, SQL sorgularını dize birleştirme yoluyla oluşturmak için yazdığınız).

Örneğin, uygulamanızda aşağıdaki gibi sahte kod yazdıysanız:

sql_stmt = "SELECT create_new_user(?, ?)"
params = (email_str, hashed_pw_str)
db_conn.execute_with_params(sql_stmt, params)

Bu SQL deyimini uygulama düzeyinde çalıştırırken SQL enjeksiyonu yapılamaz. Ancak, kullanıcı tanımlı veritabanı işlevi güvenli bir şekilde yazılmadıysa (PL/pgSQL sözdizimi kullanılarak):

CREATE FUNCTION create_new_user(email_str, hashed_pw_str) RETURNS VOID AS
$$
DECLARE
   sql_str TEXT;
BEGIN
     sql_str := 'INSERT INTO users VALUES (' || email_str || ', ' || hashed_pw_str || ');'
     EXECUTE sql_str;
END;
$$
LANGUAGE plpgsql;

sQL deyimini kullanıcı tanımlı değişkenlerin değerlerini içeren dizelerle karıştıran dize birleştirme yoluyla oluşturulan bir SQL deyimi yürüttüğü için SQL enjeksiyon saldırılarına karşı savunmasız kalırsınız.

Güvensiz olmaya çalışmadığınız sürece (dize birleştirme yoluyla SQL ifadeleri oluşturma), kullanıcı tanımlı gibi güvenli bir şekilde yazmak daha doğal olurdu:

CREATE FUNCTION create_new_user(email_str, hashed_pw_str) RETURNS VOID AS
$$
BEGIN
     INSERT INTO users VALUES (email_str, hashed_pw_str);
END;
$$
LANGUAGE plpgsql;

Ayrıca, kullanıcı tanımlı bir işlevde bir dizeden bir SQL ifadesi oluşturma gereğini gerçekten hissettiyseniz, yine de kullanıcı tanımlı bir işlevde bile depolanmış_ yordamlar/bağlı parametrelerle aynı şekilde veri değişkenlerini SQL ifadesinden ayırabilirsiniz. Örneğin PL/pgSQL içinde:

CREATE FUNCTION create_new_user(email_str, hashed_pw_str) RETURNS VOID AS
$$
DECLARE
   sql_str TEXT;
BEGIN
     sql_str := 'INSERT INTO users VALUES($1, $2)'
     EXECUTE sql_str USING email_str, hashed_pw_str;
END;
$$
LANGUAGE plpgsql;

Bu nedenle, başka bir yerde güvenli olmayan şeyler yapmadığınız sürece (yani deyimleri dize birleştirme yoluyla SQL ifadeleri oluşturuyor), hazırlanmış ifadeleri kullanmak SQL enjeksiyonundan güvenlidir.

54
dr jimbob

% 100 güvenli mi? Yakınında bile değil. Bağlı parametreler (ifadeyle hazırlanmış veya başka şekilde) etkin bir şekilde% 100, bir sınıf SQL enjeksiyon güvenlik açığı (db hatası ve aklı başında bir uygulama olmadığı varsayılarak) önleyebilir ). Hiçbir şekilde diğer sınıfları engellemezler. PostgreSQL'in (benim seçimim olan db), parametreleri belirli özelliklere ihtiyaç duymamanız durumunda hazırlanan ifadelere gidiş-dönüş kaydeden geçici ifadelere bağlama seçeneğine sahip olduğunu unutmayın.

Birçok büyük, karmaşık veritabanının kendi içinde program olduğunu anlamalısınız. Bu programların karmaşıklığı biraz değişkendir ve SQL enjeksiyonu, programlama rutinleri içinde dikkat edilmesi gereken bir şeydir. Bu gibi rutinler, tetikleyicileri, kullanıcı tanımlı işlevleri, saklı prosedürleri ve benzerlerini içerir. Birçok iyi dba'nın uygulama erişim seviyesi ile depolama seviyesi arasında bir dereceye kadar soyutlama sağladığı için, bunların bir uygulama seviyesinden nasıl etkileşimde bulunduğu her zaman açık değildir.

Bağlı parametrelerle, sorgu ağacı ayrıştırılır, ardından en azından PostgreSQL'de planlamak için verilere bakılır. Plan yürütülür. Hazırlanan ifadelerle, plan kaydedilir ve böylece aynı planı tekrar tekrar farklı verilerle tekrar yürütebilirsiniz (bu, istediğiniz gibi olabilir veya olmayabilir). Ancak asıl nokta, bağlı parametrelerle, bir parametrenin ayrıştırma ağacına hiçbir şey enjekte edememesidir. Bu yüzden SQL enjeksiyon sorununun bu sınıfı uygun şekilde halledilir.

Ama şimdi bir tabloya kimin yazdığını günlüğe kaydetmeliyiz, bu nedenle bu tetikleyicilerin mantığını kapsüllemek için tetikleyiciler ve kullanıcı tanımlı işlevler ekliyoruz. Bunlar yeni sorunlar doğurur. Bunlarda dinamik SQL varsa, orada SQL enjeksiyonu hakkında endişelenmeniz gerekir. Yazdıkları tabloların kendi tetikleyicileri olabilir. Benzer şekilde bir işlev çağrısı, başka bir işlev çağrısını çağırabilecek başka bir sorguyu çağırabilir. Bunların her biri ana ağaçtan bağımsız olarak planlanır.

Bunun anlamı, foo'; drop user postgres; -- Gibi bağlı bir parametreyle bir sorgu çalıştırırsam, doğrudan üst düzey sorgu ağacını etkileyemez ve postgres kullanıcısını bırakmak için başka bir komut eklemesine neden olmaz. Bununla birlikte, bu sorgu doğrudan başka bir işlevi çağırırsa veya çağırmazsa, hattın herhangi bir yerinde, bir işlevin savunmasız olması ve postgres kullanıcısının bırakılması mümkündür. Bağlı parametreler ikincil sorgulara koruma sağlamaz. Bu ikincil sorguların bağlı parametreleri de mümkün olduğunca kullandıklarından emin olması gerekir ve bu durumda uygun alıntı yordamlarını kullanmaları gerekir.

Tavşan deliği derinleşiyor.

Bu sorunun aşıldığı Yığın Taşması ile ilgili bir soru için BTW, bkz. https://stackoverflow.com/questions/37878426/conditional-where-expression-in-dynamic-query/37878574#37878574

Ayrıca https://stackoverflow.com/questions/38016764/perform-create-index-in-plpgsql-doesnt-run/38021245#38021245 adresinde daha sorunlu bir sürüm (yardımcı program bildirimlerindeki sınırlama nedeniyle)

25
Chris Travers