PHP PDO Sql Injection Güvenliği

Günümüzde yer alan çoğu sitede sql injection zararlı açığı mevcut. Daha öncesinde basit bir konusunu açtığım “PHP SQL İNJECTİON GÜVENLİĞİ” üzerinden sql injectionu biraz anlattım.

Sql injection nasıl işliyor önlemeniz için size biraz bilgi aktarmak istiyorum örnek bir sorgu ile:

$sorgu = 'SELECT * FROM uyeler where id = '$id'';

Sorgumuz basit uyeler içerisinden belirtilen id’yi arıyor şimdi burada injection nasıl oluyor?

Sorgu gördüğünüz üzere “” tek tırnak işareti ile sorgulanıyor $id değişkeni içerisinde şu tip bir veri girilirse:

$id = "' or uyetip = 'admin'";

Yukarıda id tırnağı kapatıp or yani id’den sonra uye tipi ile ara diyerek admin üye tipli kullanıcıları listeleyecektir yani tam olarak sorgu şöyle çalışacak:

SELECT * FROM uyeler where id = '' or uyetip = 'admin'

Yani sorguda id içerisine girilen değer ile sorguyu değiştirerek sql injection faaliyetinde bulunuluyor.

Mysql veya mysqli kullanıyorsak id değişkenlerini şu şekilde koruyabiliriz:

$id = "' or uyetip = 'admin'";
if(preg_match("/[\-]{2,}|[;]|[']|[\\\*]/", $id)) {
exit;
}

$id değişkeni zararlı içerikler belirttiği için exit; ile php işlemini durduruyor yukarıdaki işlem fakat bu her zaman etik değil çünkü örnek olarak birisi sitenize yorum yaparken tırnak işareti kullanabilir veya diğer parametrelerden herhangi birini.

Bu sırada mysql ve mysqli ile uğraşmak yerine PDO kullanacağız sakına PDO tamamen güvenli sanmayın bazı siteler veya kişiler PDO kullanınca sql injection tamamen önlenmiş gibi söylüyorlar fakat PDO üzerinde query ve exec metotları mysql ve mysqli ile aynı sorguyu yapıyorlar yani herhangi bir koruma durumu yok.

Fakat bunun içinde quote metodu geliştirilmiştir quote metodu $_GET veya $_POST üzerinden gelen verileri kontrol edebilir. Kontrol üzerinde integer ve string olarak belirterek verilerin belirli tiplerle sorgulanmasını sağlıyoruz örnek olarak:

PDO::PARAM_INT – Sayısal Veri (Integer)

PDO::PARAM_STR – Metinsel Veri (String)

// bağlantı sağlayalım
$obirconn = new PDO("mysql:host=localhost;dbname=sistem", "veritabaniuser", "veritabaniparola");
$obirconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// $_GET["id"] üzerinden gelen verimizi quote ile sayısal veri olarak kontrol edelim.
$idveri = $_GET["id"];
$idveri = $obirconn->quote($idveri, PDO::PARAM_INT);

// $_GET["hakkinda"] üzerinden gelen verimizi quote ile metinsel veri olarak kontrol edelim.
$hakkindaveri = $_GET["hakkinda"];
$hakkindaveri = $obirconn->quote($hakkindaveri, PDO::PARAM_STR);

$guncelle = $obirconn->exec("UPDATE uyeler SET hakkinda = $hakkindaveri WHERE id = $idveri");

Yukarıdaki kod üzerinde veritabanı bağlantımızı yapıp id verisini sayısal hakkında verisini metinsel olarak quote ile belirtip exec ile sorgumuzu gerçekleştirdik yukarıdaki gibi exec ve query kullanırsanız sorun yaşamazsınız.

Kolay ve güvenli şekilde prepare ile kullanırsanız kodlama açısından daha mantıklı olacaktır prepare üzerinde bindParam ile güvenli bir şekilde verileri yerleştireceğiz örnek olarak:

// bağlantı sağlayalım
$obirconn = new PDO("mysql:host=localhost;dbname=sistem", "veritabaniuser", "veritabaniparola");
$obirconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$id = $_GET["id"];
$uyenick = $_GET["uyenick"];

//Prepare ile sorgumuz içerisinde yerleştireceğimiz bindParam verilerini :veri şeklinde belirtiyoruz arından bindParam ile veriyi giriyoruz ve veri türünü belirliyoruz.
$arama = $obirconn->prepare("SELECT * FROM uyeler where uyenick = :uyenick and id = :id");
$arama->bindParam(":uyenick", $uyenick, PDO::PARAM_STR);
$arama->bindParam(":id", $id, PDO::PARAM_INT);
$arama->fetchAll(PDO::FETCH_ASSOC);
$arama->execute();

//Eğer arama sonucu var ise
if($arama->rowCount()) {
  //verileri yazdıralım
  foreach($arama as $gelenveri) {
  echo $gelenveri["uyeadi"]."<br>";
  }
}

Yukarıdaki kod üzerinde veritabanı bağlantımızı yaptık ve kod içerisinde belirttiğim gibi prepare üzerinde bindParam kullanarak verilerimizi güvenli bir şekilde yerleştirerek sorgumuzu çalıştırdık eğer ilk defa yapıyorsanız ve sorgu çalışmıyor ise sorunu şu şekilde yazdırabilirsiniz örnek olarak:

$arama->execute($array) or print_r($arama->errorInfo(), true);

Array ile çıktıda size sorgu üzerindeki hataları gösterecektir sizde kontrol ederek sorgunuzu düzeltebilirsiniz.

Ek olarak INSERT örneği

// bağlantı sağlayalım
$obirconn = new PDO("mysql:host=localhost;dbname=sistem", "veritabaniuser", "veritabaniparola");
$obirconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$uyeadi = $_GET["uyeadi"];
$uyenick = $_GET["uyenick"];
$uyetip = "normal";
$uyesitesi = "obir.ninja";

$ekle = $obirconn->prepare("INSERT INTO uyeler(uyeadi, uyenick, uyetip, uyesitesi) VALUES (:uyeadi, :uyenick, :uyetip, :uyesitesi)");
$ekle->bindParam(":uyeadi", $uyeadi, PDO::PARAM_STR);
$ekle->bindParam(":uyenick", $uyenick, PDO::PARAM_STR);
$ekle->bindParam(":uyesitesi", $uyesitesi, PDO::PARAM_STR);
// hata var ise yazdır
$ekle->execute($array) or print_r($ekle->errorInfo(), true);

Yukarıdaki kod üzerinde uyeler’e insert yani ekleme işlemi gerçekleştirdik ve :uyeadi, :uyenick ve :uyesitesi olarak belirttiğimiz verileri bindParam ile yerleştirdik ve veri tipini belirterek güvenli hale getirdik.

Bu şekilde sorgu güvenliğini gerçekleştirebilir rahat bir şekilde sorgu yaptırabilirsiniz unutmadan söyleyeyim eğer like kullanacaksanız sorguyu şu şekilde yapmanız gerekiyor örnek olarak:

Yanlış bindParam sorgusu:

$uyenick = $_GET["uyenick"];
$arama = $obirconn->prepare("SELECT * FROM uyeler where uyenick like %:uyenick%");
$arama->bindParam(":uyenick", $uyenick, PDO::PARAM_STR);

Doğru bindParam sorgusu:

$uyenick = $_GET["uyenick"];

$uyenicklike = "%".$uyenick."%";
$arama = $obirconn->prepare("SELECT * FROM uyeler where uyenick like :uyenick");
$arama->bindParam(":uyenick", $uyenicklike, PDO::PARAM_STR);

Yani burada sorgunun içerisine %:uyenick% yerine sade bir şekilde :uyenick ekleyip bindParam verisinin içine %veri% olarak girdik ve sorgu başarılı bir şekilde çalıştı.

PDO ile sql injection korumamız bu kadardı daha fazla güncel konular için obir.ninja’yı takip etmeyi unutmayın.

One thought on “PHP PDO Sql Injection Güvenliği

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir