PHP ile Basit SQL Injection Önleme Yöntemleri

Dökümanın Forum Konusu Linktedir : http://www.tahribat.com/Forum-Dokuman-Php-Ile-Basit-Sql-Injection-Onleme-Yontemleri-163524/

SQL Injection Nedir?

SQL Injection kısaca veritabanı işlemlerinizde sorgularınızın başka kişiler tarafından zararlı hale getirildiği işlemdir. Bu sorun genellikle kullanıcıdan gelen bilgilerin kontrol edilmeden, filtrelenmeden işleme konulması ile ortaya çıksada basit bir unutkanlık bile buna yol açabilir.

SQL Injection sistemleriniz için oldukça tehlikelidir. Kullanılan yönteme göre kimi zaman veritabanınızın boşaltılması, kimi zamanda veritabanınızın bir yedeğini bir başkasının eline geçmesini sağlayabilir. Hatta içerik yönetim sistemine sahip bir sisteme sahipseniz yönetici hesabınızın başkasının eline geçmesi sonucu sisteminize geriye dönüşü olmayan hasarlar verilmesini sağlayabilir.

Bu makalede SQL Injection hakkında dikkat edilmesi gereken temel başlıklardan söz edeceğim.

Tarayıcı Tarafında Dikkat Edilmesi Gerekenler

 Dikkat edilmesi gereken 2 ana başlık var. Web sayfası tarafında dikkat edilmesi gerekenler ve sayfa işlenirken dikkat edilmesi gerekenler. Bu başlıkta web sayfasında, yani veri daha işleme konulmadan dikkat edilmesi gerekenlerden bahsedeceğim.

Sayfalarımızda temel girdi çıktı işlemlerini formlar veya form elemanları aracılığı ile gerçekleştiriyoruz. Mesela basit bir form düşünelim. Formda basit alanlarımız olsun. Kullanıcı adı ve  şifre girilmesini istediniz. Siz bu alanlara yalnızca belirli sayıda karakterlerin girilmesini istiyorsunuz. Html tagleri ile limitlerinizi tanımladınız. Artık kullanıcı adı ve şifre bölümlerine örneğin 10 karakter girilmesini sağlıyorsunuz. Ama baktınız bu yetmiyor. Kullanıcı adına yalnızca alfanumerik karakterler girilsin dediniz. Js -javascript- ile bunu da gerçekleştirdiniz. Artık formunuz gayet düzgün bir şekilde, istediğiniz gibi işliyor... Böyle düşünüp işinize devam ederseniz yanılırsınız. Bu tanımlamalara hiçbir zaman güvenmemeniz gerekiyor. Kullanıcı sayfasının üzerinde firebug ve benzeri programlar aracılığı ile her türlü manipülasyon (güncelleme, değiştirme vs) işlemleri yapılabiliyor. Siz 10 karakter sınırı koyarsınız, kullanıcı bunu alır 20 yapar. Siz buna güvenip sayfanız işlenirken herhangi başka bir sorgu eklemezseniz kullanıcı rahatlıkla 20 karakterli bilgisini veritabanına kaydetmeyi başarır. Js ile sadece harf girilmesini sağladığınızı düşündünüz. Kullanıcı tarayıcısındaki js desteğini kapattığı an tüm sorgunuz de-aktif hale gelir. Bunlar bu örnekte basit gibi görünsede bir çok kişi bu hatayı yapıp daha sonrasında formu işlerken herhangi bir kontrol yapmadan geçiştiriyor. Bu da takdir edersiniz ki çok büyük bir güvenlik açığına sebep oluyor.

Ayrıca sayfalarınıza başka bir dil veya sayfa aracılığıyla da bilgi gönderilebilir. Alan adları uygun şekilde ayarlandıktan sonra bir başkası kendi hazırladığı sayfayı sizin sayfanızdan geliyormuş gibi gönderebilir ve çalışmasını sağlayabilir. Sunucu tarafında gerekli önlemleri almayıp sayfanızdaki önlemlere güvendiğinizde yine çok büyük bir kapıyı hırsızlar için açık bırakmış oluyorsunuz.

Sayfa İşlenirken Dikkat Edilmesi Gerekenler

Yukarıda sayfamızı hazırlarken dikkat etmemiz gerekenleri görmüştük. Şimdi bu sayfayı sunucu tarafında işlerken dikkat etmemiz gerekenlerden bahsedelim.

Üstteki örnekten devam edelim. Formumuz yine kullanıcı adı ve şifre alanlarını içersin. Kullanıcı adı ve parola alanlarına max. 10 karakter girilmesini ve kullanıcı adında yalnızca alfanumerik karakterlerin girilmesini isteyelim.

Bunu sunucu tarafında nasıl sorgulayabiliriz diyebilirsiniz. PHP'nin yerleşik kütüphanesinde bu işlemler için bir dizi komut tanımlıdır. Bunlardan isteğinize uygun olanları kullanabilirsiniz. Ayrıca bu komutlar sizin için yetersizse regular expression (düzenli ifadeler) kullanarak ve tanımlayarak istediğiniz kontrolün yapılmasını sağlayabilirsiniz. PHP'nin içindeki bazı komutları ve ne işe yaradıklarından bahsedelim.

Altta gösterdiğimiz komutları kullanabilmeniz için php versiyonunuzun en az 4.0.4 olması gerekmektedir. Ayrıca fonksiyonlar geriye dönüş değeri olarak true/false döndürür.

ctype_alnum(): Girdinin tüm karakterlerinin alfanumerik karakterlerden oluşup oluşmadığını sorgular. Alfanumerik; a-z arası alfabe karakterleri (Türkçe karakterler hariç) ve 0-9 arası rakamları kapsar.

http://php.net/manual/tr/function.ctype-alnum.php

ctype_alpha(): Girdinin tüm karakterlerinin alfabetik karakterlerden oluşup oluşmadığını sorgular. Alfabetik karakterlerin içerisinde Türkçe karakterler yer almaz. Türkçe karakterlerle ilgili sorgunun nasıl yapılacağını altta ayrıca göstereceğim.

www.php.net/manual/tr/function.ctype-alpha.php

ctype_lower(): Girdinin tüm karakterlerinin küçük harflerden oluşup oluşmadığını sorgular. ctype_upper() tam tersi, büyük harfleri sorgular.

http://www.php.net/manual/tr/function.ctype-lower.php

http://www.php.net/manual/tr/function.ctype-upper.php

Ctype komutları dışında işinize yarayabilecek diğer fonksiyonlar şöyledir.

is_float(): Girdinin float/double tipinde (10.2 gibi) olup olmadığını sorgular.

http://se2.php.net/manual/tr/function.is-float.php

is_bool(): Girdinin mantıksal true/false tipinde olup olmadığını sorgular. 1/0 gibi değerler false döner.

http://se2.php.net/manual/tr/function.is-bool.php

empty(): Girdinin boş olup olmadığını sorgular. Aşağıdaki karakterler boşluk olarak ele alınır;

0 (bir tamsayı olarak 0)
"" (boş bir dizge)
"0" (bir string olarak 0)
NULL
FALSE
array() (boş bir dizi)
var $var; (bir sınıf içinde bir değeri olmaksızın bildirilmiş bir değişken)

http://se2.php.net/manual/tr/function.empty.php

is_int(): Girdinin tamsayı olup olmadığını sorgular.

http://se2.php.net/manual/tr/function.is-int.php

is_numeric(): Girdinin sayısal bir tür olup olmadığını sorgular. Bilimsel gösterimler (1e5), tamsayılar ve noktalı sayıları kapsar.

http://se2.php.net/manual/tr/function.is-numeric.php

isset(): Girdide belirtilen değişkenin tanımlı olup olmadığını sorgular. Değişken null değer içeriyorsa da false döndürür.

http://se2.php.net/manual/tr/function.isset.php

strlen(): Girdinin karakter sayısı uzunluğunu döndürür.

http://php.net/manual/en/function.strlen.php

Yerleşik, işinize yarayabilecek komutlar ve ne işe yaradıklarından bahsettik. Üstte alpha ve alnum komutlarının Türkçe karakterlerini sorgulamadığını söylemiştim. Şimdi onları nasıl kontrol edebileceğinizden ve birkaç farklı sorgudan bahsedelim.

Eğer girdinin içerisinde Türkçe karakter geçip geçmediğini sorgulamak isterseniz;

if(preg_match("/[ığüşçöİ]/i","kontrol edilecek girdi"))
echo "Türkçe karakter içeriyor";

Eğer girdinin yalnızca Türkçe karakterleri içerecek şekilde alfabetik karakterlerden oluşup oluşmadığını sorgulamak isterseniz;

if(preg_match("/^[a-zığüşçöİ]+$/iu","kontrol edilecek girdi"))
echo "Alfabetik karakterlerden oluşuyor";

Üstteki işlevin alfanumerik için olanı;

if(preg_match("/^[a-z0-9ığüşçöİ]+$/iu","kontrol edilecek girdi"))
echo "Alfanumerik karakterlerden oluşuyor";

Bu fonksiyonlar neredeyse tüm form işlemlerinize yetecek, güvenilir fonksiyonlardır. Gelen verinin hangi tipte ve nasıl olmasını istiyorsanız bunlardan uygun olanlar ile sınamamız gerekiyor.

Verilerin Filtrelenmesi

Script tarafında yapmamız gereken ikinci işlem verilerimizi filtreleme işlemi olmalıdır. Bir üst maddede verilerimizin tiplerini ve biçimlerini sorgulamayı öğrenmiştik. Bu aşamada ise verilerimizi kullanırken yani veritabanı ile iletişime girerken yapmamız gerekenlerden bahsedeceğim.

Bu iki madde aslında birbirlerini tamamlayan maddelerdir. İkisinden birisini atlamanız halinde bir açık kapı bırakmış olursunuz. Benim size önerim bu iki maddedeki kurallara uyup o şekilde yolunuza devam etmeniz olur. Başkaları sizin sisteminize sızmak için sizin yaptığınız hataları, bıraktığınız arka kapıları ararlar. Eğer tembellik edip, bunu da bırakırsam bir şey olmaz bulamazlar şeklinde düşünürseniz ileride olası bir durumun tohumlarını ekmişsiniz demektir.

Filtreleme aşamalarını maddeleyecek olursak;

1.      Kullanıcıya hiçbir zaman güvenmeyin..En ufak ihtimali dahi gözden kaçırmadan dikkatli bir şekilde yolumuza devam etmemiz gerekiyor. En büyük düşmanımız kullanıcılarımızdır.

2.      Veritabanındaki metinsel alanlara girdi yaparken girdileri tek tırnakların arasına alın.

insert into test (isim,soyisim) values ('test','deneme')

3.      Sorgulardaki db ismi, tablo adı, kolon adları, takma isimler gibi tanımlayıcılarda yatık tırnak (`) kullanın.

select `isim`,count(*) as `toplam` from `tablomuz` ...

4.      Tüm girdilere kaçış (escape) işlemi uygulayın. Bu işlem girdinizdeki veritabanına tehdit oluşturabilecek karakterlerin önlenip zararsız hale getirilmesini sağlar.

Mysql veritabanı için: mysql_real_escape_string(girdi)

5.      Sorgularda özel anlamı bulunan % ve _ karakterlerine ayrıca escape işlemi uygulayın. addcslashes() komutu 2. parametrede belirtilen karakterlere escape işlemi uygulayan yararlı bir komuttur.

$girdi=addcslashes($girdi,”%_”)
select xx from `tablom` where isim like '$girdi%'

6.      Veritabanındaki sayısal alanlara girdi yaparken verinin belirttiğiniz türde olduğundan emin olmak için intval() tarzı komutları kullanın. intval belirtilen girdiyi tam sayıya çevirir. Float türü için floatval() komutunu kulanabilirsiniz.

7.      Sorgumuzda “order by girdi” şeklinde bir ifade kullanırken girdide belirtilen alan adının tablodaki alanlardan bir tanesi olup olmadığını sorgulayın.

$res=mysql_query(“show columns from tablomuz”);
while($row=mysql_fetch_row($res))
$tabloAlanlari[]=$row[0];
if(!in_array($girdi,$tabloAlanlari))
$girdi=”belirleyeceğinizDefaultKolonAdı”;

8.      Veritabanınızdan sadece sayfanızda kullanacağınız kadar bilgiyi alın.

9.      SQL'e ait bazı özel kavramları ASCII karşılıklarıyla, emsalleriyle güncelleyin.

$girdi=str_ireplace("where","&#119here",$girdi);
$girdi=str_ireplace("drop","&#100rop",$girdi);
$girdi=str_ireplace("select","&#115elect",$girdi);
$girdi=str_ireplace("union","&#117nion",$girdi);
$girdi=str_ireplace("like","&#108ike",$girdi);
$girdi=str_ireplace("update","&#117pdate",$girdi);
$girdi=str_ireplace("delete","&#100elete",$girdi);
$girdi=str_ireplace("insert","&#105nsert",$girdi);
$girdi=str_ireplace("show","&#115how",$girdi);
$girdi=str_ireplace("alter","&#97lter",$girdi);

Bunlar düz kullanımlarda geçerli olan kurallardır. Birde PHP'nin içerisinde yerleşik olarak bulunan PDO dediğimiz hazır veritabanı yapıları mevcuttur. Bunları kullanarak zahmetsiz, seri ve güvenilir bir şekilde sorgularınızı hazırlayabilirsiniz. PDO'yu kullanabilmek için PHP versiyonunuzun en az 5 olması gerekmektedir.

PHP PDO: http://tr.php.net/manual/tr/book.pdo.php

Özetle benim söyleyeceklerim bu kadar. Bu kurallara dikkat ettiğiniz müddetçe, veritabanınızın güvenliğini de gerekli şekilde sağladınız müddetçe pek problem yaşamayacağınızı düşünüyorum.

Eksiklerim, atladığım noktalar elbette olabilir. Bunlara dikkat ettiğiniz halde yine sorunlar yaşayabilirsiniz. Bunlar sizin kodlamalarınıza, davranışlarınıza, güvenlik bilginize göre ortaya çıkabilir. Sisteminizin sorunsuz olmasını istiyorsanız mutlaka bilgili bir veya birkaç kişiye sisteminizi test ettirin. Hatta imkanınız varsa sisteminizi kullanıcı testlerine sokun. En iyi sorun bulma yöntemi bu şekildedir. Ne kadar çok kişi sisteminizi test ederse o kadar sorunsuz bir sisteme sahip olursunuz.

Tarih:
Hit: 265
Yazar: Austen

Taglar: php ile basit sql injection önleme yöntemleri


Yorumlar


Siftahı yapan siz olun
Yorum yapabilmek için üye girişi yapmalısınız.