Web Sitelerinde Veritabanı Kullanımı ve Güvenliğin Önemi
Günümüzde birçok web sitesi kullanıcılar ile etkileşim sağlamak ve gerekli bilgileri saklamak amacıyla veritabanı kullanmaktadır. Facebook gibi sosyal amaçlı siteler, alışveriş siteleri, forumlar, haber siteleri, bloglar vb birçok sitede içerikler veritabanında saklanır.
Bu tarz sitelerde genellikle şu mantık kullanılır. Sayfaların belli yerleri sabittir ve tüm sayfalarda aynıdır. Bazı yerler ise kullanıcının komutuna göre veritabanından getirilerek oluşturulur.
Örneğin bir haber sitesinde sayfanın orta kısmında haberin başlığı, resimleri, içeriği ve yorumları veritabanından alınarak oraya yerleştirilir. Hangi habere ait bilgilerin veritabanından getirileceği sql sorguları ile gerçekleştirilecektir.
Yani kullanıcının talebine göre belli sorgular çalışacak ve veritabanındaki ilgili tablolardan veriler alınarak sayfaya yerleştirilecektir.
Çok kullanışlı olan bu yöntem aynı zamanda tehlikelidir de. Çünkü veritabanımız için yeterli güvenlik önlemleri almadıysak, bilgilerimiz çalınabilir, değiştirilebilir ya da zarar verilebilir. Veritabanımız indirilmeye karşı güvenli bir klasörde yer alsa ve bağlanmak için kullanıcı adı ile parola gerekse bile farklı yöntemler ile bilgilerimize hala ulaşılabilir.
Sql injection denilen yöntem de bunlardan biridir.
Sql injection nedir, örnekle açıklayalım.
QueryString Kullanımında Sql Injection Riski
Bir haber sitemiz olsun ve kullanıcının tıkladığı haberlere ait ayrıntılar haber.aspx sayfasında gösteriliyor olsun. Yani tüm haberler için tek bir sayfamız var. Bu sayfa veritabanından gelen bilgilere göre dolduruluyor.
Genelde tercih edilen yöntem linklere querystring kullanarak o haberin id’sinin eklenmesidir. (bizim sitemizde de bu yöntemin kullanıldığını adres çubuğuna baktığınızda göreceksiniz.) Kullanıcı bir haberin linkine tıkladığında o haberin id’si adrese eklenerek ilgili sayfaya gönderilir.
Ardında o sayfa açılırken gelen id bilgisi sql sorgusu içerisinde kullanılarak sorgulama yapılır ve ilgili habere ait bilgiler getirilir.
Bu şekilde anlatıldığında çok kullanışlı bir yöntem olarak gözükse de son derece tehlikelidir. Çünkü querystring içerisindeki bilgi adres çubuğunda açıkça gözükmekte olup kolayca değiştirilebilir.
Buradaki id bilgisi yerine gerekli sql kodları yazılırsa sorgu apayrı işlemler gerçekleştirebilir. Veritabanından ilgili habere ait kaydı getirmek yerine tüm bilgileri değiştirebilir, kopyalayabilir ya da farklı işlemler yapabilir.
Çok basit bir örnek gösterelim:
-
Kullanıcı 101 numaralı habere tıklasın ve 101 bilgisi haber.aspx sayfasına querystring ile gönderilsin.
-
Haber.aspx sayfasında kullandığımız sql sorgusu şöyle oluşacaktır:
SELECT * FROM haberler WHERE haberId = 101;
-
Normalde bu sorgu çalışacak ve 101 nolu haber getirilecektir.
-
Ancak adres çubuğunda görünen 101 bilgisi silinerek 101;DROP TABLE haberler şeklinde değiştirilirse sayfadaki sorgu şu hale gelecektir.
SELECT * FROM haberler WHERE haberId = 101; DROP TABLE haberler;
-
Bu basit yöntem bile haberler tablomuzun silinmesine neden olacaktır.
-
Çok daha gelişmiş sorgular kullanılarak farklı işlemler gerçekleştirilebilir.
Peki önlem olarak ne yapılabilir.
Burada ilk yapmamız gereken şey, querystring ile gelen bilginin direkt olarak sorguya yerleştirilmemesi, öncelikle tehlikeli ifadelerden temizlenmesi ondan sonra sorgudaki yerine konmasıdır. Bunun içinde farklı yöntemler kullanılabilir. (Diğer yöntemlerden daha aşağıda bahsedeceğiz)
Mesela C# kullanıyorsak QueryString içindeki bilgiyi alıp replace metodu ile şu şekilde temizleyebiliriz. metinTemizle diye bir metot oluşturalım:
protected string metinTemizle(string a)
{
string[] tehlikeliIfadeler = {"--", ";", "@@", "@", "char", "nchar", "varchar", "nvarchar", "alter", "begin", "cast", "create", "cursor", "declare", "delete", "drop", "end", "exec", "execute", "fetch", "insert", "kill", "open", "select", "sys", "sysobjects", "syscolumns", "table", "update"};
foreach (string ifade in tehlikeliIfadeler)
{
a= Regex.Replace(a, ifade, "x");
}
return a;
}
Page_PreInit içerisinde QueryString’teki bilgiyi alarak temizleyelim. Hatta temizlenen bilgiyi session nesnesine yazıp, sorgu oluşturulurken session içindeki temizlenmiş bilgiyi kullanabiliriz.
protected void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["haberId"] != null)
{
string haberNo = Request.QueryString["haberId"];
haberNo = metinTemizle(haberNo);
Session.Add("haberId", haberNo);
}
}
Yukarıdaki örnekte QueryString içindeki haberId bilgisi haberNo değişkenine alınmış, ardından metinTemizle metodu ile güvenli hale getirilerek Session nesnesi içine haberId ismiyle yazılmıştır.
metinTemizle metodu içindeki diziye istediğimiz ifadeleri ekleyip çıkarabiliriz.
Kullanıcı Girişi Sırasında Sql Injection
Sql injection’a maruz kalabileceğimiz işlemlerden biri de kullanıcı girişidir. Kullanıcının kullanıcı adı ve parolasını girdiği iki metin kutusu kullanıyor ve bunlara girilen verileri direkt olarak sorguya yerleştiriyorsak yine aynı tehlikeyle karşı karşıyayız demektir.
Kullanıcı ilk kutuya Ahmet parolaya da 1234 girdiğinde sorgumuz şuna benzer olacaktır:
SELECT * FROM kullanicilar WHERE UserName = ‘Ahmet’ And PassWord=’1234’
Metin kutusuna daha önce bahsettiğimiz gibi tehlikeli ifadeler girilebilir. İlk metin kutusuna şu ifade yazılırsa;
sorgu şu hale gelecektir:
SELECT * FROM kullanicilar WHERE UserName = ‘Ahmet’ or 1=1--
Burada 1=1 ifadesi her zaman doğru olacağı için oturum açılmış olacaktır. -- ifadesi sorgunun kalan kısmının devre dışı kalmasını sağlar.
Bu örnektekinden çok daha farklı yöntemler de kullanılabilir.
Burada da önlem olarak metin kutularına girilen bilgiler temizlenerek sorgu içine yerleştirilmelidir.
Başka bir Sql Injection örneği;
kullaniciAdi = getRequestString("UserName");
parola = getRequestString("UserPass");
sqlSorgusu = "SELECT * FROM Users WHERE userName ='" + kullaniciAdi + "' AND password ='" + parola + "'"
" or ""=" şeklinde bir ifade kullanıcı adı olarak girildiğinde sorgu aşağıdaki hale gelecek ve tüm kullanıcı adlarına erişilebilecektir.
SELECT * FROM Users WHERE userName ="" or ""="" AND password ="" or ""=""
Bu sorgudaki şart (where) kısmı her halikarda doğru sonuç döndüreceğinden sql injection gerçekleştirilebilecektir.
Sql Injection Engelleme Yöntemleri
Tehlikeli ifadeleri temizleme yöntemi sık kullanılan bir yöntemdir ve yukarıda bahsedilmiş, örnek kodları da gösterilmiştir. Bu yöntemin dezavantajlarından biri normalde veritabanına eklemek isteyeceğimiz zararsız ifadelerin de engellenmesine yol açabilmesidir.
Mesela tek tırnaklar sql sorgusu içinde tehlikeli olabilir, ancak zaman zaman kendimiz de tek tırnak içeren metinler eklemek isteyebiliriz. Tek tırnağı zararsız biçimde veritabanına eklemek için şöyle bir c# kodu kullanılabilir.
a = Regex.Replace(a, "'", "'");
Tek tırnaktan başka ifadeler de (@, ? gibi) tehlikeli sayılarak normalde zararsız bile olsa engelleneceği için kara liste yöntemi çok da kullanışlı olamamaktadır. Ama işinizi görecekse kullanabilirsiniz.
Daha farklı yöntemlere de göz atalım.
Sql Parametreleri Kullanarak Sql Injection Engelleme
Sql parametreleri programlamadaki değişkenler gibi düşünülebilirler. Sql sorgusuna çalışma zamanında kontrollü biçimde yerleştirilirler.
ASP.NET Razor Örneği
kullaniciAdi = getRequestString("UserId");
sorgu = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(sorgu, kullaniciAdi);
Örnekte de görüldüğü gibi sql parametreleri @ karakteri ile başlayacak şekilde isimlendirilir.
Sql parametreleri çalıştırılmadan önce Sql Engine tarafından kontrol edilir, dolayısıyla tehlikeli ifadeler engellenmiş olur.
Yukarıdaki örnek geliştirilebilir:
isim = getRequestString("adi");
mesaj = getRequestString("msg");
sehir = getRequestString("sehir");
sorgu = "INSERT INTO mesajlar (isim,mesaj,sehir) Values(@0,@1,@2)";
db.Execute(sorgu,isim,mesaj,sehir);
Bu örnekler farklı şekillerde çoğaltılabilir:
Asp.Net Güvenli Select Sorgusu Örneği:
konuNo = getRequestString("konuId");
sorgu = "SELECT * FROM konular WHERE konuId = @0";
command = new SqlCommand(sorgu);
command.Parameters.AddWithValue("@0", konuNo);
command.ExecuteReader();
Asp.Net Güvenli Insert Sorgusu Örneği:
adi = getRequestString("adiniz");
mesaj = getRequestString("msg");
yas = getRequestString("age");
sorgu = "INSERT INTO mesajlar (adi,mesaj,yasi) Values(@0,@1,@2)";
command = new SqlCommand(sorgu);
command.Parameters.AddWithValue("@0",adi);
command.Parameters.AddWithValue("@1",mesaj);
command.Parameters.AddWithValue("@2",yas);
command.ExecuteNonQuery();
PHP Güvenli Insert Sorgusu Örneği:
$stmt = $dbh->prepare("INSERT INTO mesajlar (adi, mesaj, yasi)
VALUES (:isim, :mesaji, :yasi)");
$stmt->bindParam(':isim, $isminiz);
$stmt->bindParam(':mesaji, $mesaj);
$stmt->bindParam(':yasi', $yasiniz);
$stmt->execute();
Querystring sql injection önleme, c# asp.net ve php ile sql injection önleme, sql injection engelleme yöntemleri, kara liste yöntemi, sql parametreleri kullanımı, güvenli sql sorguları oluşturma
KONU İLE İLGİLİ ÖRNEKLER
Bu konu ile ilgili örnek bulunmamaktadır.
19813 kez okundu.