PHP'de CSRF/XSRF Açıklarından Korunma

Wiki.Pardus-Linux.Org sitesinden

Git ve: kullan, ara

PHP'de CSRF/XSRF Açıklarından Korunma

Şimdi CSRF/XSRF [Cross Site Request Forgery] açıklarından nasıl korunacağımızı göreceğiz. XSRF Çogu Web Uygulamasında kullanılabiliyor. Mesela Hotmail... Gmail'de olduğundan ise şüpheliyim. Herneyse şimdi konumuza geçelim.

Ufak bir portal düşünün:

Admin.php
index.php
admin_yazdi.php
admin_giris.php

Burada Admin.php ana sayfaya yazacağı metni gösteriyor. admin_yazdi.php ise POST Methodu ile gelen veriyi index.php üzerine yazıyor. Evet, güzel bir sistem, değil mi? XSS/CSS açıklarını da önledik. Güvendeyiz, değil mi?

Peki burada admin_yazdi.php'ye biz sadece şöyle bir şey yazarsak?

<body onload="document.CSRF.submit()">
<form name="CSRF" method="POST" action="http://www.url.*/portal/admin_yazdi.php" style="display:none">
<input type="text" name="yazilar" value="izinsiz yazılar">
</form>
</body>

Yukarıdaki kodlar ile bizim konumuzun ne alakası var?

Burada admin_yazdi.php'ye dışardan POST metodu ile veri gönderiyoruz. O da ne yapsın, kodlayanı dinliyor ve yazılar alanındaki değeri (value) index.php üzerine yazıyor. Şu an kafanızda bir şeylerin şekillendiğini hissediyorum.Yazımıza ziyaretçi defteri uygulaması ile devam edelim:

index.php;

<?php
include("ayar.php");

echo "<div align=\"center\">
   <table border=\"0\" width=\"75%\" cellspacing=\"0\" cellpadding=\"0\">
   <tr>
      <td>
      <fieldset><legend>Ziyaretci Defteri Formu</legend> 

<form action=\"mesajkayit.php\" method=\"post\">

<div align=\"center\">

<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">
   <tr>
      <td colspan=\"3\">
      <p align=\"center\">Mesajınızı Kaydedin</td>
   </tr>
   <tr>
      <td>Adınız Soyadınız</td>
      <td>:</td>
      <td><input type=\"text\" name=\"adisoyadi\" size=\"20\"></td>
   </tr>
   <tr>
      <td>Email Adresiniz</td>
      <td>:</td>
      <td><input type=\"text\" name=\"email\" size=\"20\"></td>
   </tr>
   <tr>
      <td>Mesaj Başlığı</td>
      <td>:</td>
      <td><input type=\"text\" name=\"baslik\" size=\"20\"></td>
   </tr>
   <tr>
      <td>Mesajınız</td>
      <td>:</td>
      <td><textarea rows=\"7\" name=\"mesaj\" cols=\"34\"></textarea></td>
   </tr>
   <tr>
      <td> </td>
      <td> </td>
      <td><input type=\"submit\" value=\"Mesajı Gönder\"><input type=\"reset\" value=\"Formu Temizle\"></td>
   </tr>
</table>

</div>

</form>
      
      </fieldset>
      
      
      </td>
   </tr>
</table></div>
";
//--- Mesaj Listeleme Başlangıç

$limit   = 1;
$sira   = $_GET["sira"];
if(($sira=="") or !is_numeric($sira)){
$sira   = 1;
}

   $satirsayisi   = mysql_num_rows(mysql_query("SELECT * FROM mesajlar"));
   $toplamsayfa   = ceil($satirsayisi / $limit);
   $baslangic      = ($sira-1)*$limit;
   

$sor = mysql_query("SELECT * FROM mesajlar ORDER BY id DESC LIMIT $baslangic,$limit");
echo "Syfalar : ";
for($x=1; $x<=$toplamsayfa; $x++){

echo "<a href=\"index.php?sira=$x\"> $x </a> |";

}

echo "<div align=\"center\">
   <table border=\"0\" width=\"75%\" cellspacing=\"0\" cellpadding=\"0\">";


While($yaz=mysql_fetch_array($sor)){
$adisoyadi   = $yaz['adisoyadi'];
$baslik      = $yaz['baslik'];
$tarih      = $yaz['tarih'];
$mesaj      = $yaz['mesaj'];
$email      = $yaz['email'];
echo "<tr>
      <td>
      
      
      <fieldset><legend>$adisoyadi</legend>
<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">
   <tr>
      <td>$baslik</td>
   </tr>
   <tr>
      <td><hr></td>
   </tr>
   <tr>
      <td>$mesaj</td>
   </tr>
   <tr>
      <td>
      <br><br><p align=\"right\">$email / $tarih</td>
   </tr>
</table>

</fieldset>
          
      </td>
   </tr>";

}

echo "</table></div><br>";
echo "Syfalar : ";
for($x=1; $x<=$toplamsayfa; $x++){

echo "<a href=\"index.php?sira=$x\"> $x </a> |";

}


?>

Ayar.php;

<?php

$dbhost      = "localhost";
$dbuser      = "root";
$dbpass      = "";
$dbadi      = "ziyaretcidefteri";
   
   $baglan      = mysql_connect($dbhost,$dbuser,$dbpass);
   if(! $baglan) die("Mysql bağlantısı sağlanamıyor");
   
   mysql_select_db($dbadi,$baglan) or die("Veritabanı bağlantısı sağlanamıyor");


Function Filitre($text){
$gelenmesaj      = array("<",">","refresh","lcation","script","\n");
$yenimesaj      = array("<",">","ref>esh","lca>ion1","scr>pt","<br>");

$son   = str_replace($gelenmesaj,$yenimesaj,$text);
return $son;

}

?>

mesajkayit.php;

<?php
include("ayar.php");


$adisoyadi   = $_POST["adisoyadi"];
$email      = $_POST["email"];
$mesaj      = Filitre($_POST["mesaj"]);
$baslik      = Filitre($_POST["baslik"]);
$tarih      = date("d.m.Y  H:i:s");


if($baslik==""){

echo "<center>Lütfen Başlık Belirtin";
header("Refresh: 2; url=index.php");

}else{


   $ekle   = mysql_query("INSERT INTO mesajlar (adisoyadi,email,mesaj,tarih,baslik) values ('$adisoyadi','$email','$mesaj','$tarih','$baslik')");
      if($ekle){
      
      echo "<center>Mesajınız Kaydedildi</center>";
      header("Refresh: 2; url=index.php");
      }else{
      
      echo "<center>HATA <BR>Mesajınız Kaydedilemedi</center>";
      header("Refresh: 2; url=index.php");
      
      
      }   

}
?>

Yukarda bulunan ziyaretci defteri uygulamasında filtre uygulanmış ve ziyaretçi defterine yazmak için;


$adisoyadi   = $yaz['adisoyadi'];
$baslik      = $yaz['baslik'];
$tarih      = $yaz['tarih'];
$mesaj      = $yaz['mesaj'];
$email      = $yaz['email'];

degişkenleri bizden isteniyor. Bunların Boş-Dolu kontrolünü de uygulayarak, uzaktan POST GET yapılmasını önlemek için GÜVENLİK KODU oluşturabiliriz. Bu kod Doğru ise işlem devam edecek, Yanlış ise
"Güvenlik Kodu hatalı!
Tekrar Deneyiniz."

şeklinde bir uyarı verecek.

XSRF Türkiye'ye geldiği demeyelim de tanındığı zamanlarda XSS/CSS 'den daha etkili olduğunu söylediler. Karar sizin; hangisi daha etkili?

XSRF'nin Türkiye'de çogu sistemde olduğunu da söylemek istiyorum. Konu hakkında http://forum.pardus-linux.org adresindeki Web Programlama Bölümü'nde uygulama güvenliği ile sorularınızı bekliyorum.

Bu arada XSRF/XSS Sadece PHP'de olmaz. Burada PHP'yi kötülemiyorum, aksine, ASP'de oluşabilecek bug'ları yazmaya Pardus-Kwrite dayanamayacağı için bunlarla yetiniyorum. Bu yazılardan sonra Hotmail değil, Gmail; Windows değil, PARDUS; Internet Explorer değil, FIREFOX kullamanız dileğiyle.

Hazırlayan : S3pd0x
Amaç  : Güvenli Bir Web.
e.posta  : ynlfehhz[at]gmail[nokta]com / s3pd0x[at]x-ss[nokta]info # Sadece Mail.