Php ve Mysql İle Güvenli Oturum Açmayı Sağlama (Session login hack için önlemler)

Öncelikle şunu belirtmek isterim ki bir şey ne kadar güvenli olursa olsun tamamen güvenli değildir. Ancak yeterince güvenli olabilir. Yani, aşılamayacak güvenlik önlemi yoktur. O yüzden yaptığınız işe bakıp “oh be ne iş çıkardım içeri sittin sene giremezler.” demeyin. Bir yazılım asla bitmiş değildir ve bir yazılım asla tam koruma altında değildir. Gelişen yazılım dünyasının güvenlik kısmını da takip edip sürekli bir güncelleme içinde olmak gerekiyor. Bugün güvenli olan bir kod öbeği yarın bir açık tehdit olabiliyor.

Bu yazı oturum açma - giriş - login script'i yazarken hangi noktalara dikkat etmeniz gerektiğini anlatır, size hazır bir script sunmaz.

İlk olarak "son kullanıcılara hiç bir zaman güvenmeyin" diye kulağınıza küpe bir cümle ile giriş yapmış olalım.

Kullanıcı girişlerine (input) güvenmek yapılacak hataların başını çeker. Kullanıcıların doğru kutucuğa doğru formatta bilgi gireceğini hiç bir zaman düşünmeyin. Söz gelimi kullanıcı adı bölümünde kullanıcıdan girmesini beklediğiniz bilgi “hasanhuseyin” , “aliveli4950″ gibi bir şeydir. Ancak kullanıcının bu bölüme     ‘ or ” = ‘    girmeyeceğini (Bknz: SQL injection) kim garanti edebilir? Bu yüzden hardcoded olarak değerini atamadığınız ve bir sorguda kullanacağınız her değişkeni stripslashes(), addslashes() gibi fonksiyonlarla işleyiniz.

Kısaca Sql inject
Bir login scripti yazarken nihayi olarak yazacağınız kod ve sql kodu şunun gibi olacaktır:

<?php
$kullanici_adi = $_POST['kullanici'];
$parola = $_POST['parola'];
$sonuc = @mysql_query("SELECT * FROM kullanicilar WHERE kullanici = ‘" . $kullanici_adi .
    "‘ AND parola = ‘" . $parola . "‘ LIMIT 1");
if (@mysql_num_rows($sonuc) > 0)
    echo 'Sistemime hoş geldin';
else
    echo 'Hatalı kullanıcı adı ya da parola';
?>

Eğer bu kodu bu şekliyle yazarsanız. Çok ağlarsınız. Yukarıda da bahsettiğim gibi eğer kullanıcı adı bölümüne sizin beklediğiniz gibi aliveli4950 yazılmaz da ‘ OR ” = ‘ yazılırsa veri tabanına göndereceğiniz sorgu şu hale gelir:

SELECT * FROM kullanicilar WHERE kullanici = ‘‘ OR ” = ‘‘ AND parola = ‘kullanicinin girdiği herhangi birşey’ LIMIT 1

Bu sorgu veri tabanındaki ilk kayda parola bölümünde ne yazarsa yazsın girer. Aynı model kullanıcı adının bilindiği parolanın bilinmediği durumlarda da işe yarar. Bu yüzden SQL sorgusuna göndereceğiniz tüm kullanıcı kaynaklı verileri önce addslashes() fonksiyonu (Regular-Expressions ile de mümkün) ile işleyin.

Aynı injection modeli çerezlerde (cookie) ve get metoduyla aldığınız verilerde de geçerlidir es geçmeyin.

Örneğin şöyle bir bağlantınız var:

./kullanici-sil.php?id=17

Hiç kontrol yapmadan bu id değişkenini sql sorgusuna gönderirseniz. Gene ağlayabilirsiniz. Adresin sonuna kullanıcının şu satırcıkları eklediğini düşünelim

./kullanici-sil.php?id=17‘ OR 0 = 0 #

Sıfır her zaman sıfıra eşittir. Bir de bire. İki ise ikiye… Yani her zaman geçerli olacak ufacık bir kod yumağı sizi ne hale getirir düşünün. (Örnekte yetkilendirme kontrolü verilmemiştir, yapın tabi kullanıcı silerken bakın bakalım bunu isteyen kullanıcının bu işleme yetkisi var mı? Öyle her önüne gelen kullanıcı silse.. ohoooo. )

id gibi sadece rakamsal olmasını beklediğiniz değişkenleri is_integer() fonksiyoncuğuyla kontrol etmeniz yeterlidir.

  • Paylaşılan sunucularda sessionları veritabanında tutun.

Sessionlar güvenlik açısından sağlamdır. Ancak eğer paylaşılan bir sunucu kullanıyorsanız hangi session u hangi ip adresi için açtığınızı veri tabanında tutun. Paylaşılan sunucularda php temp dizini aynı yerde olacağı için o sunucudaki herhangi bir site sizin siteniz için geçerli bir session oluşturabilir. Bunu engellemenin yegâne yolu da hangi session u (session_id()) hangi ip adresine açtığınızı bir tabloda tutmaktır.

  • Parolaları SHA-1 ile şifreleyin

Veri tabanında parolaları tutmak için char(40) alan oluşturun. Oluşturduğunuz bu alana kayıt yaparken ya da parola kontrolü yaparken sha1() fonksiyonunu kullanın.

Örneğin

$pasword = '123456';
echo sha1($password); // 10470c3b4b1fed12c3baac014be15fac67c6e815 gibi bir çıktısı olacaktır.
  • Kullanıcılara ek bilgi vermeyin.

Bunu ürettiğiniz her hata mesajı için yapın. Örneğin bir giriş formunda “kullanıcı adınız yanlış” ya da “parolanız sondaki 6 rakamı eksik”  gibi mesajlar vermeyin. Sadece “geçersiz giriş denemesi” ya da “geçersiz kullanıcı adı ve/veya parola” deyin.

  • Hataları yakalayın.

Php de birçok fonksiyon hata ya da uyarı mesajları gösterir. Bu uyarı ya da hata mesajlarının ekranda gözükmesi geliştirme süresince sizin yardımcınız olsa da, son kullanıcıya hitap eden bir sistemde yalnızca saldırganlara hizmet eder.

Örneğin:

Warning: file_exists() [function.file-exists]: open_basedir restriction in effect. File(/usr/local/lib/php/extensions/no-debug-non-zts-20060613/../../../../../../home/ioncube/ioncube_loader_lin_5.2.so) is not within the allowed path(s): (/home/rxsex:/usr/lib/php:/usr/local/lib/php:/tmp) in /home/rxsex/public_html/fonksiyon.php on line 2

Tarzı bir hata mesajı hangi dosyanızın hangi satırında hangi işlemleri yapmaya çalıştığınızla ilgili bilgi içeriyor. Bu hata mesajlarını fonksiyonların başlarına @ işareti getirerek susturabilirsiniz. Daha sonra da işlemin başarıyla gerçekleşip gerçekleşmediğini sonuç değişkenlerinden (her fonksiyon döndürür) ya da mysql_affected_rows() gibi fonksiyonlarında yardımıyla öğrenip hata yada başarı mesajlarınızı kullanıcıya gösterin.

  • HTTP_REFERER i kontrol edin.

HTTP_REFERER istemini bulunduğunuz sayfa kullanıcının buraya hangi adresten geldiğini döndürür. Ancak aldatılması kolaydır. Sadece bir kaç çaylağı ve basit spam botlarını engeller. Çok güvenmeyin ama yine de kullanın.

  • Gelen bilgileri kırpın.

Örneğin kullanıcı adı kutucuğunuz en fazla 32 karakterden oluşacaksa önce input kutusunun “maxlength” özelliğini kullanın sonra da substr() gibi fonksiyonlar yardımıyla kırpın.

Örnek

<input type="text" maxlength="32" name="kullaniciadi">
<?php
$kullaniciadi = substr($kullaniciadi,0,32);
?>
  • $_POST kullanın $_REQUEST değil!

Sayfaya post metoduyla gönderdiğiniz bilgileri $_POST ile alın $_REQUEST ile değil. $_REQUEST get metoduyla gönderilmiş formlarında bilgilerini alır.

  • Sorgu sonlarına LIMIT 1 ekleyin

Tek sonuç döndürmesini / işlemesini beklediğiniz her sorgunun sonuna LIMIT 1 özelliğini ekleyin.

  • IP adresini engelleyin!

Birçok kez login denemesinde başarısız olan ip adresini geçici bir süreliğine engelleyin. (15 dk?) Yada yine geçici bir süreliğine resim kontrollü (captcha) giriş ekranına yönlendirin.

  • Log tutun

Kritik hataların ve giriş denemelerinin loglarını tutun.

Örneğin

$result = @mysql_query($query) or die("Öldü bu, olmadı bu sorgu");

Yerine

$result = @mysql_query($query) or logla_baboli("Hata dosyası: ABCD.php, satır: 56", mysql_error(), $kullanici, time());

daha sonra da $result değişkenine göre sayfada hata veya başarı mesajı çıkartın.

  • Global değişkenlere dikkat!

Global değişkenleri register etme php.ini dosyasında aktif edildiyse (register_globals = On) sayfa global değişkenleri GET metoduyla atanabilir olur. Deneyin:

<?php
if ($kacki_bu_sayi > 0 )
echo "Yok artık...";
?>

bunu yerel sunucumuzda test dizinin altına test.php olarak kaydettik ve şu adrese girdik diyelim

http://localhost/test/test.php

adres bu şekilde yazdığımızda hiç bir sorun yok. Sayfa beyaz ötesi ace kıvamında. Ancak şu şekilde yazarsak:

http://localhost/test/test.php?kacki_bu_sayi=2

o zaman sayfa ebemizin kulaklarını çınlatıyor.

Bunu engellemenin 2 güzide yolu mevcut.

1: php.ini dosyasında register_globals özelliğini kapatın (register_globals = off)

2: Eğer php.ini dosyasına erişiminiz yoksa her değişkenin işlemden önceki değerini atayın.

Örnek:

<?php
$kullanici_giris_yaptimi = false;
//if (giriş kontrolü kodu)
$kullanici_giris_yaptimi = true;
?>

Son olarak SSL

Daha fazla güvenlik için giriş scriptlerinizde SSL kullanın.



2 yorum

  • Yorumunuz en az 30 karakter olmalıdır. (0)
    Tüm Yorumlar
    • TEKNO BURGER

      Çok teşekkür ederim. Çok yararlı bir yazı olmuş... Neyse

      Yanıtla

    • ufuk

      Güzel yazı olmuş teşekkürler.

      Yanıtla

Sitede Ara
  • CS 1.5 ve CS 1.6 İçin Sağlam Bir CFG (cengaver.cfg)
    güzel bir cfg tavsiye ediyorum...
  • Soyut Kavramlara Örnekler
    Abi somut yazsaydın da yine olmazdı. ...
  • Evcil Kuş Hastalıkları ve Tedavi Yöntemleri
    Merhaba, geçmiş olsun bu durumda kendi başınıza tedavi uygulamanız zor olsa da kırık çıkık için tıklayı...
  • Finansal Yönetim Ders Notları | 1-7
    gerçekten emeğinize sağlık çok güzel bir anlatım olmuş....
  • Yazımı Karıştırılan Sözcükler | TDK Yazım Kılavuzu | Doğru Kelime Klavuzu
    Atölye Fransızca'dan dilimize geçmiş bir isimdir. Fransızca atelier olarak yazılır. Evet atelye ...
  • Online Cetvel Sitesi
    Bu ayarları yaptıktan sonra elimdeki cetvelle test ettim gerçekten doğru gösteriyor. Ekrana tuttuğum ce...
  • Doğal Varlık Nedir - Anlamı ve Örnekler
    Çook sevdim bu siteyi... ...