Sunucu Güvenliği : SQL Injection

Adı üzerinde SQL enjeksiyonu. Kelime bence tam olarak oturmuyor ama konuyu terimsellestirmek için yazılmış. Sanki SQL’e bir virüs enjekte ediliyor gibi bir anlam çıkartıyor insan ilk duyduğunda. Oysa tam olarak SQL’e SQL enjekte edilerek yapılıyor bu saldırı.

Diyelim ki bir kullanıcı giriş formunuz var. Bu formda haliyle kullanıcı adı, şifre ve CSRF ataklarini onlemek için kullandığınız captcha değerini alıyorsunuz. Hatta SSL güveliği tam olarak kapsıyor sitenizi ve XSS saldırılarından korunmak ile ilgili tüm tedbirleri de aldınız. Fakat hala acemice/dikkatsizce yazılmış bir kodunuz varsa veya çok eski bir php4 ya da php5 kodu çalıştırıyorsanız bir açığınız olabilir. SQL kodlarının bir enjeksiyon denemesi ile tamamlanarak veritabanı sorgularınızın bozulup bozulamayacağını bilmiyorsunuz. Örnek verirsek;

gibi bir formunuz var diyelim. Normalde bu kisimdaki beklentiniz kullanici adi kismina kullanici adi ya da eposta yazilmasi. Sizin de bunu PHP gelistiricilerinin coktandir tavsiye etmedigi ama hala pek cok eski kitapta yer alan mysql_* fonksiyonlari ile kontrol ettiginizi dusunelim. Basitlestirince soyle bir sorgunuz var demek oluyor;

Bu sorgu yaptigi kontrolde username alani yerine peki bu kod gelirse ne olacak;

Sorgumuz bu durumda kullanici adi bos veya 1=1 ise anlamina geldi. Bu şekilde saldırgan sadece bu alanı değil aynı zamanda captcha ya da parola alanlarını da kullanabilir. Yani tüm sorguyu istediği hale getirebilir. PHP geliştiricileri bu noktada önceden kendi classlarini kullanarak tek tırnak veya çift tırnak gibi karakterleri regex filtreleri ile temizliyorlardı. Addslashess, mysql_real_escape_string gibi bazı fonksiyonlar kullanılıyordu. Fakat bu yeni PHP versiyonlarında mysql driverlerin yerini mysqli ve PDO aldığı zaman değişti.

Örneğin bir PDO baglantısında dışardan aldığınız verileri için sorgunuzu şu şekilde hazirladığınızda SQL injection riskiniz ortadan kalkıyor.

Ayni şekilde ( ben bu noktada PDO kullanmanizi tavsiye ettigim icin mysqli sorgusunu sona koyuyorum ) mysqli için de bunun bir yolu var.

Bu noktada güvenliğin bir maliyeti oldugunu da söylemek gerek. Mysqli performansi %1-5 arası sorguya gore mysql_* ile karsılaştırıldığında düşebiliyor. Fakat zaten mysql_* için yazılacak veya kullanılacak kodların da performansa etkisi olacağı için bunu görmezden gelebiliriz.

Bu yazıda SQL Injection ile ilgili örnekler vermiş oldum. Bunu kendi kodunuza uyarlayarak güvenliği arttırabilirsiniz. Zaten artık mysql_* yeni PHP sürümlerinde kullanılmayacak. Fakat injection mantığını öğrenmek, özellikle kullanıcıdan gelen veriye güvenmemek refleksinizi korumalısınız.

Herkese iyi çalışmalar…

Guncelleme (15 Ekim 2017):

Bir de SQL Injection icin sunucu ayarlari kapsaminda alinabilecek bir tedbir var. Apache modullerinden security modulu ile SQL Injection aciklarinin onune gecilebiliyor. Bunun icin modulu sonradan kurmaniz gerekiyor cunku default kurulumda gelmiyor. Ayrica bu konu icin bir yazi yazacagim.