2011-05-14 18 views
25

Bir uygulamayı SQL enjeksiyondan korumalıyım. Uygulama, ADO kullanarak Oracle'a bağlanıyor ve kimlik doğrulaması yapmak için kullanıcı adı ve parola aranıyor.Delphi - SQL enjeksiyonuna karşı önlem

Şimdiye kadar okuduğumdan, en iyi yaklaşım, tüm SQL'i dize olarak atamayarak parametreler kullanmaktır. Böyle bir şey: Ayrıca

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 
query.Prepare; 
query.ParamByName('Name').AsString := name; 
query.ParamByName('ID').AsInteger := id; 
query.Open; 

, ben kullanıcı girişi doğrulamak ve silme, ekleme seçeneğini, vb ... ASCII harfler ve rakamlar normalden daha farklı Herhangi giriş karakteri gibi SQL kelimeleri silmek düşünüyorum silinecek.

Bu, en az güvenlik düzeyini garanti eder mi?

Delphi 7 standardı ve Jedi'den başka bileşen kullanmak istemiyorum.

cevap

40

Güvenli

query.SQL.Text := 'select * from table_name where name=:Name'; 

Bu kod güvenlidir.
Parametreler, SQL-enjeksiyondan her zaman güvenlidir. Kullanıcı adı aşağıdaki sorguda Ortaya name; Drop table_name; yürütülmektedir olabilir çünkü

Güvensiz

var Username: string; 
... 
query.SQL.Text := 'select * from table_name where name='+ UserName; 

güvensiz mi.

select * from table_name where name=name; Drop table_name; 

Ayrıca Güvensiz

var Username: string; 
... 
query.SQL.Text := 'select * from table_name where name='''+ UserName+''''; 

adı ' or (1=1); Drop Table_name; -- ise o Aşağıdaki sorguda neden olur çünkü:

select * from table_name where name='' or (1=1); Drop Table_name; -- ' 

Ama bu kod güvenlidir

Hiçbir SQL kodu, sorgu dizesine yalnızca sayıları bu şekilde enjekte edilebilir böylece IntToStr() sadece

(tam olarak ne istediğinizi ve bu nedenle izin veren) tamsayılar kabul eder Ama yapmak istediğim

var id: integer; ... query.SQL.Text := 'select * from table_name where id='+IntToStr(id); 

Çünkü

Parametreler ile yapılamayan parametreler sadece değerler için kullanılabilir. Alan adlarını veya tablo adlarını değiştiremezler. Yani tablo veya alan adları için parametreleri kullanamazsınız çünkü ilk sorgu başarısız olur bu sorgu

query:= 'SELECT * FROM :dynamic_table '; {doesn't work} 
query:= 'SELECT * FROM '+tableName;  {works, but is unsafe} 

yürütmek istiyorum.
İkinci sorgu güvenli değil, ancak bunun yapılabilmesi için tek yoldur.
Nasıl güvenli kaldınız?

Onaylanmış adların bir listesine karşı tablename dizesini kontrol etmeniz gerekir.

Const 
    ApprovedTables: array[0..1] of string = ('table1','table2'); 

procedure DoQuery(tablename: string); 
var 
    i: integer; 
    Approved: boolean; 
    query: string; 
begin 
    Approved:= false; 
    for i:= lo(ApprovedTables) to hi(ApprovedTables) do begin 
    Approved:= Approved or (lowercase(tablename) = ApprovedTables[i]); 
    end; {for i} 
    if not Approved then exit; 
    query:= 'SELECT * FROM '+tablename; 
    ... 

Bunu yapmanın tek yolu bu, bildiğim.

BTW Orijinal kod bir hata var:

query.SQL.Text := 'select * from table_name where name=:Name where id=:ID'; 

tek bir (alt) sorgusu

+0

Teşekkür ederim Johan. Soruyu düzelttim. + 1 – RBA

+0

+1 birden fazla senaryoyu örtmek için –

+0

Ama yine de SQL parametresini 'name; Tablo_adı; Drop kullanıcı tarafından girildiğinde, bu tür giriş kutusuna –

6

This will assure me a minimum of security level?

Evet, parametrized sorgular sizi sınamak kolay olan SQL enjeksiyonundan korumalıdır. name değişkeninde bazı tehlikeli dizeleri girin ve ne olduğunu görün. Normalde 0 satır döndürmeli ve bir hata almamalısınız.

12

Kullanıcının etki alanı olan bir sql komut metnine bağlanacak parametrelerin değerini yalnızca etkilemesine izin verirseniz, gerçekten kullanıcının girdiği şeyi incelemeye gerek yoktur: SQL'den kaçınmanın en kolay yolu Sunulan gibi, birleştirilmiş SQL'den kaçınmak ve bağlı değişkenleri (veya çağrıları çağırmak) kullanmak bunu yapar (aynı zamanda, motorun sorgu planlarını yeniden kullanmasına izin vermenin avantajı - kilometre/alaka düzeyine de bağlıdır).

Eğer Oracle kullanıyorsanız, o zaman ciltli değişkenleri kullanarak değil için gerçekten iyi bir neden olması gerekir: Tom Kyte onun sitesinde http://asktom.oracle.com bu konuda iyi bilgi ton vardır. Arama kutusuna "ilişkili değişkenler" girmeniz yeterlidir. Eğer parametreleri kullanarak çünkü

+1

+1 iki where 's olamaz

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 

olmalı - SQL enjeksiyonundan kaçınmanın en iyi yolu, kablo üzerinden SQL göndermektir. – Vector