SQL Enjection Saldırısından Korunma

SQL Enjeciion Nedir?
Günümüzde pek çok projede veritabanı kullanımlarına şahit olabiliriz. Başta, Facebook, Google gibi firmalar dahil olmak üzere veritabanı kullanımı oldukça önem kazanmaya başlamıştır. Veritabanları üzerinde veri ekleme, silme, okuma, vs. Gibi işlemler SQL dili aracılığıyla olmaktadır. Tabi bu işlemler yapılırken bazı güvenlik açıkları oluşuyor. Herhalde günümüzün en popüler açıklarından biri de SQL Enjection açığıdır. SQL Enjection açığı, programcının kullanımı olduğu SQL sorgularına dışarıdan müdahale edilerek oluşmaktadır. Basit örnek olarak, bir sisteme giriş yapmak için üyelik sistemi düşünelim:

<!DOCTYPE html>
<html>
<head>
<title>SQL Enjection Önleme</title>
</head>
<body>
<form action="" method="GET">
Kullanıcı Adı : <input type="text"
Kullanıcı Şifre :<input type="text"
cinput type="submit" name="gonder"
</form>
</body>
</>

Buradaki Giriş Formuna sıradan bir üye giriş yapmak istemektedir. Üye kullanıcı adı Tekno, şifre teknoltan olduğunu varsayalım. Üyenin sistemde kayıtlı olduğunu öğrenmek için veritabanında bir sorgu çalıştırmamız gerekiyor:

Üyeler ismi altında bir Tablo’muz olduğunu düşünürsek ve bu tabloda bulunan satırlar sırayla; uye_id, uye_ad, uye_sifre, uye_email olduğunu farz edelim. tekno isimli kullanıcının, sistemde olup olmadığını test etmek için amaçlı şu SQL sorgusu çalıştırılabilir:

SELECT * FROM üyeler WHERE uye_ad=”tekno” AND uye_sifre=”teknoltan” Şayet üye sistemde var ise, Veritabanındaki bilgileri bize dönecektir ve bu bilgilere sisteme giriş yapılacaktır. İşte SQL Enjection açığı ise tam bu esnada ortaya çıkmaktadır. Yukarıda verdiğimiz örnekte girilen değerleri kullanıcı girecektir. Peki herhangi bir kullanıcının kullanıcı adı kısmına ” ‘ OR 1=1 ve şifre kısmına ” ‘ OR 1 = 1 girdiğini düşünelim bu durumda arkada çalıştırılan SQL sorgusu şu şekilde olacaktır:

SELECT * FROM üyeler WHERE uye_ad=”” ‘ OR 1=1 ‘ AND uye_sifre=”” ‘ OR 1=1 ‘ Bu SQL sorgusunda uye_ad sütunundaki, boş veya 1 değerindeki elemanlar ve uye_sifre sütunundaki, boş veya 1 değerindeki elemanları listeleyecektir. Böyle bir sorgu sonucunda veri tabanımızda sürekli olarak olumlu sonuç dönecek ve saldırgan sisteme giriş yapacaktır.

En basitinden, olayı bu şekilde özetleyebiliriz. Böyle bir güvenlik probleminin, nasıl sonuçlar yol açacağını sanırım az çok tahmin ettiğinizi düşünüyorum. Peki oldukça tehlikeli görünen bu SQL Enjection açığından nasıl korunabiliriz? Bunun için alınabilecek önlemlerden bazıları şu şekilde listeleyebiliriz;

-> SQL Enjection açığından korunmak için, kullanıcı ile etkileşimde olduğumuz alanlarda, aldığımız değerleri filtrelememiz gerekmektedir. Örneğin SQL sorgularında kullanılan, ‘ (tek tırnak) ve ” (çift tırnak) gibi meta karakterlerin, geçişinin önlenmesi ile bu açıktan kısmen korunabiliriz.

-> Hatalı olabilecek sorgularda veritabanı hatalarının engellenmesi gerekmektedir. Örneğin; siteadi.com/id?=4 gibi bir sitede, ziyaretçinin id değerinin sonuna ‘ (tek tırnak) koyması ile sistemde SQL açığı var ise, hata döndürmeye neden olacaktır. Bu gibi hataların gizlenmesi sistemi biraz daha güvenli kılacaktır.

-> Veritabanında mutlaka bir WAF (Web Application Firewall) kullanmaya çalışın. Sqlmap gibi bazı araçlar aracılığıyla veritabanının çözümlenmesini biraz zorlamaya çalışmanız gerekmektedir.
-> Özellikle kullanıcıdan karakte yerine sayı bekleyeceğimiz durumlarda, kullanıcının sayı girdiğinden emin olmak için ISNUMERIC fonksiyonuyla, kontrol edilmesi güvenlik oalrak bir nebze daha artış gösterecektir. SQL Enjection’un ne olduğunu artık anladığımıza göre, esas konumuz olan PHP’de SQL açığının nasıl önlenebileceğini inceleyelim.. Not : SQL Açığı sadece Web Projelerinde değil, veritabanı kullanılan tüm projelerinizde meydana gelebilir. Ancak biz bu konuda sadece PHP ile bu açığı nasıl önleyebileceğimizi inceleyeceğiz.
-> PDO İle Daha Temiz Kod ve Daha Güvenli Kod Yazın PHP’in eski sürümlerinde, veritabanı işlemlerimiz için mysql* ile başlayan fonksiyonları kullanmamız gerekirdi. Örnek olarak GET ile alınan bir veriyi mysql fonksiyonları ile bir sorgu yaptırmak için aşağıdaki kodu yazabiliriz:

$sorgu - 'SELECT * FROM üyeler WHERE uyead="' .$_GET["ad"].'"
AND uyesifre="'.$_GET["sifre"].'"';
$sonuc mysql query($sorgu);

Görüldüğü gibi burada SQL Enjection açığı oluşturmak mümkün buradaki SQLGörüldüğü gibi burada SQL Enjection açığı oluşturmak mümkün buradaki SQLaçığını gidermek için, SQL’deki tüm meta karakterlerin sorguya girişini önlemek gerekiyordu. Peki bunu nasıl yapabiliriz? Örnek olarak aşağıdaki kaynak kodu inceleyelim:

$filtre "select union count where	from ' ""
	
(strstr($ GET["ad"], Sfiltre)	strstr($GET["şifre"], $filtre))
{	
header("location:./404.php");	

Filtre değişkenini istediğiniz kadar uzatabilirsiniz. Böylelikle saldıganın girdiği veri eğer Filtre değişkeninin içerisindeki kelimelerden biriyse otomatik bir şekilde 404.php sayfasına yönlendirilecektir. Buradaki filtre değişkenimize aslında ‘ (tek tırnak) ve ” (çift tırnak) girmemiz yeterli olacaktır. Mesela şimdi de şöyle bir şey deneyelim:

$ad=str replace("'","", $_GET["ad" ]);
$sifre=str replace("'","", $_GET["sifre" ]);
$sorgu= 'SELECT * FROM üyeler WHERE uyead="'.$ad.'" AND uye sifre="'.$sifre.'"'
$sonuc mysql query($sorgu);

Eskisine göre biraz daha düzenli bir kod oldu, buradaki yapılan işlemde ise kullanıcının ‘ (tek tırnak) girmesi durumunda, bu karakteri silmesini sağlayacaktır. Böylelikle de kullanıcı ‘ (tek tırnak) kullanamayacağından dolayı, sistemimiz bir nebze daha güvenli olmuş olacaktır. Şimdi gelelim PHP’de PDO olayına.. Yuakrıda kullanmış olduğumuz mysql fonksiyonları PHP7 itibarıyla kaldırılmış bulunmaktadır. Bunun yerine ise iki eklenti gelmiş bulunmakta, mysqli ve PDO ile veritabanı işlemlerimizi gerçekleştirebiliriz. Ancak sınıf yapısı yapımından PDO kullanımı daha güvenli ve daha temizdir. Örnek olarak şimdi yukarıda Mysql fonksiyonalrı kullanarak, yazmış olduğumuz sorguyu bir de PDO ile yazalım:

PDO ile sorgumuzu bu şekilde gerçekleştirebiliriz, Burada dikkat etmeniz gereken husus ise prepare ile sorgumuzu gerçekleştirirken ? Bıraktığımız yerlerde sırayla, girilecek değerleri girmemiz gerekmektedir. Yukarıda gerçekleştirdiğimiz önlemlerin çoğunu PDO’da execute aracılığıyla yapmaktayız. Bu sayede hem daha anlaşılır bir kod hemde daha güvenli bir sistem geliştirebilirsiniz.. Not : Burada anlaşılır olması açısından GET kullanılmıştır, daha güvenli işlemlerde POST kullanarak veri gönderimi yapınız..

Yorum yapın