Güvenli PHP Uygulamaları – Formların Güvenliği

Betiklerimize istemediğimiz yerlerden form verilerinin gönderilmesiyle ortaya çıkar.

Aşağıdaki gibi bir formumuz(form.php) olsun:

<form action="formIsle.php" method="POST">
	<input type="radio" name="medeniHali" value="bekar" checked="checked">
	<input type="radio" name="medeniHali" value="evli">
	<input type="radio" name="medeniHali" value="dul">
	<input type="submit" value="Gönder" />
</form>

Bu formu işleyen sayfamız(formIsle.php) ise aşağıdaki gibi olsun, formdan gelen medeni hali bilgisini yazdırıyor.

1
2
3
4
<?php
echo $_POST['medeniHali'];       
// Çıktı: bekar
?>

Saldırganın aşağıdaki formu(form.php) kendi bilgisayarından gönderdiğini varsayalım. Formun action özelliğine tam adresi yazıyor.

1
2
3
4
<form action="http://www.siteadresi.com/formIsle.php" method="POST">
	<input type="text" name="medeniHali" value="yalancı">
	<input type="submit" value="Gönder" />
</form>

Form işleyen(formIsle.php) sayfamız yukarıda gönderilen formu işler.

1
2
3
4
<?php
echo $_POST['medeniHali'];
// Çıktı: yalancı
?>

Medeni hali, bekar-evli-dul değerlerinden birini alması gerekirken, “yalancı” diye bir değer almıştır.

Bunu önlemek için tek kullanımlık bir şifre oluşturulabilir:

1
2
3
4
5
6
7
8
9
10
11
<?php 
$formAnahtar = rand(10000,1000000);
$_SESSION['formAnahtar'] = $formAnahtar;
?>
<form action="http://www.siteadresi.com/formIsle.php" method="POST">
	<input type="radio" name="medeniHali" value="bekar" checked="checked">
	<input type="radio" name="medeniHali" value="evli">
	<input type="radio" name="medeniHali" value="dul">
	<input type="hidden" name="formAnahtar" value="<?php echo $formAnahtar; ?>">
	<input type="submit" value="Gönder" />
</form>

Formu işleyen(formIsle.php) sayfamız:

1
2
3
4
5
6
7
<?php
 
if($_SESSION['formAnahtar'] == $_POST['formAnahtar'])
	echo $_POST['medeniHali'];
else 
	echo "Bu form başka bir yerden geliyor.";
?>

Güvenli PHP Uygulamaları – Cross site scripting(XSS)

Kullanıcının betiklerimize html kodu enjekte etmesiyle ortaya çıkar.
Girdi filtrelenmeden çıktı olarak sunuluyorsa bu saldıya uğranabilir.

Aşağıdaki gibi bir formumuz olsun:

1
2
3
4
<form id="form1" action="" method="post">
<textarea name="mesaj"></textarea>
<input type="submit" value="gönder" />
</form>

Formdaki mesaj alanına aşağıdaki javascript kodunun enjekte edildiğini varsayalım.

1
2
3
<?php 
<script type="text/javascript">window.location = 'http://www.zihni.net' </script>
?>

Girdiyi filtrelemeden, aşağıdaki şekilde ekrana yazdırırsak, sayfaya giren her kullanıcıyı istediğimiz siteye yönlendiririz.

1
2
3
<?php 
echo $_POST['mesaj'];
?>

Yukardaki kodun zararlı etkilerinden korunmak için girdiyi htmlentities() işleviyle filtrelememiz gerekir.

1
2
3
<?php 
echo htmlentities($_POST['mesaj']);
?>

Güvenli PHP Uygulamaları-Sql enjektelerine karşı önlemler

Veritabanına gönderilen her bir değişken mysql_real_escape_string()
işlevinden geçirilerek sql enjeksiyonlarına karşı önlem alınabilir.
Bu işlev veritabanları için özel anlamı olan karakterleri escape-kurtarma işlemine tabii tutar,
bu karakterlerden bazıları: \n, \r, \, ‘, ”

Aşağıdaki gibi kullanıcı adı ve şifre alanlarından oluşan bir giriş formumuz olsun:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>mysql_real_escape_string</title>
</head>
<body>
<form name="form1" action="" method="post">
Kullanıcı adı:<input type="text" name="kullanici_adi" value="" /> <br />
Şifre<input type="password" name="sifre" value="" /> <br />
<input type="submit" value="gönder" name="gonder" /></div>
</body>
</html>

Kullanıcının formdan aşağıdaki bilgileri gönderdiğini varsayalım.

1
2
$_POST['kullanici_adi'] = 'zihni';
$_POST['sifre'] = "' OR ''='";

Kullanıci adi ve sifre verilerinin veritabanında olup olmadığını kontrol edelim

3fe3cd4b1e9ba348921f50a5fa9561f8012

mysql’e gönderilen sorgu aşağıdaki gibi olur:

1
SELECT * FROM kullanicilar WHERE kullanici_adi='zihni' AND sifre='' OR ''=''

Görüldüğü gibi sifre geçersiz olsa bile sorgu sonucu başarılı olur.

Eğer formdan gelen bilgileri mysql_real_escape_string() işlevinden geçirdikten sonra veritabanına gönderirsek:

1
2
3
4
5
6
7
8
9
10
11
<?php
$sorgu = sprintf("SELECT * FROM kullanicilar
WHERE kullanici_adi='%s' AND sifre='%s'",
mysql_real_escape_string($_POST['kullanici_adi']),
mysql_real_escape_string($_POST['sifre']) );
 
$sonuc = mysql_query($sorgu) or die(mysql_error());
$satir = mysql_fetch_array($sonuc);
echo $satir['kullanici_adi'];
echo $sorgu;
?>

mysql’e gönderilen sorgu aşağıdaki gibi olur ve bir sonuç döndürmez.

1
SELECT * FROM kullanicilar WHERE kullanici_adi='zihni' AND sifre='\' OR \'\'=\''