PHP Sistemlerin Güvenliği Nasıl Sağlanmalıdır?
1. Birinci Düzey Öneme Sahip Güvenlik Önlemleri
Şirketler, web yazılımlarında Arşivlerini ve personel bilgilerini barındırdıklarından WEB sistemlerinin güvenliği çok önemlidir. Sistemlerin güvenliğinin sağlanmasında kullanılabilecek bazı yollar şunlardır;
Veri tabanında şifreleri password_hash(PHP) kullanarak Algoritmik + Salt + MD5 olacak şekilde şifreli tutmak, Müşteri ve personellerin telefon numaraları gibi önemli verileri MD5 kullanarak şifreli biçimde tutmak; Veri Tabanına bağlanan kullanıcının yetkilerini kısıtlı tutmak, DROP, ALTER, UPDATE ve DELETE gibi komutları sistem dışında(LOGİN) kullanılan veri tabanı kullanıcısının kullanımına engellemek. SQL İnjection’a karşı anlık tespit ve uyarı sistemi barındırma; Kullanıcıdan alınan her türlü GET ve POST verisine güvenmemek, bunları mysql_escape_real_string() gibi fonksiyonlar kullanarak kullanıcıdan alınan girdileri filtrelemek gerekir ancak bu fonksiyon tam anlamıyla güvenli değildir, mysql yerine PDO veya mysqli kullanmak bir çok güvenlik açığını otomatik olarak kapatmamıza yardımcı olacaktır zaten PHP’nin yeni sürümünü kullanıyorsanız mysql kullanmanıza izin vermeyecektir; Sisteme giriş yapmaya çalışan her türlü kişinin tarayıcı, IP,zaman,sayfa konumunun kayıt altına alınması; İnputlarda veri girişinde sadece özel karakterlerin girişine izin verilememesi (Email girdileri dışında.); Giriş Yapılan sistemde yetki seviyeleri belirlenmesi, her kullanıcı için yetki belirlenip yeni kayıt olan kullanıcının yetkisi veri tabanında NULL olarak atılması gerekir. Böylelikle bir saldırgan her türlü önleme rağmen sisteme bir şekilde giriş yapmaya başarırsa veri tabanında yetkisi bulunmadığından sistemde hiçbir sayfaya erişim hakkı olmayacak kısa süre içinde yöneticiler tarafından fark edilip hesabı silinebilecektir. Sistemlerde bir kayıt[LOG] servisinin oluşturulması zorunludur. Hangi kullanıcının hangi sayfada ne işlem yaptığı yöneticisi tarafından görüntülenebilmelidir. Sistem içinde anlık engelleme sistemi bulunmalıdır. Bir kullanıcı sistemden engellendiği anda sistemden çıkış yapmalı ve bilgilendirme mesajı göstermelidir. Bu sistemde kullanıcının engellendiği anda tespit edip sistemden çıkarması son derece önemlidir, çünkü siz bir kullanıcıyı engellediğinizde normal şartlarda kullanıcı sayfayı yenilemeden veya başka bir sayfaya geçmeden sistemi kullanmaya devam edebilir. Bunun önüne geçmek için gerçek zamanlı engelleme sistemi barındırılmalıdır; PHP için her sayfada işlem yapmadan önde POST veya GET, if/else ile zorunlu tutulmalıdır, POST veya GET ile girilmesi gereken bir yere kullanıcının veri göndermeden girmesini önlemek gerekir. $_REQUEST kesinlikle kullanılmamalıdır kullanımı
halinde hangi verinin nerden geldiği sistem tarafından belirlenmesi zorlaşacak ve sistemimizde istenmeyen sonuçlar oluşturabilecektir; Sorgular için WhiteList oluşturulmalı sadece SELECT isteyen sorguda DROP kullanımın önüne geçilmelidir; Formlara php ile veri limiti koymak, mesela kullanıcı adının az çok kaç karakterden oluşacağı bellidir. Max 25 koyduğumuzu düşünelim, 25 karakterden fazlasına hata verebilir veya veriyi direk hiç işlemeden geçebilir bu sayede URL Encode, Desimal ve Heksadecimal gibi salıdırlardan kaçınmış oluruz; Gelen veri türünün php tarafınca kontrol edilmesini sağlamamız gerekir, kullanıcıdan bir tam sayı isteniyorsa is_int(), yazı isteniyorsa is_string() kullanılarak gelen veriyi tür bakımından filtre etmiş oluruz; Oturum güvenliğini sağlamak için kesinlikle HTTPS/SSL protokolü kullanılmalı gelen ve giden veri uçtan uca şifrelenmiş olmalıdır. Son olarak PHP yazılımımızın yeni sürümlerini kullanmamız kesinlikle önemlidir. Örneğin File Inclusion gibi sızma teknikleri PHP’nin son sürümlerinde onarılmıştır.
1.1 Mysql_escape_real_string(); fonksiyonu neden yeteri kadar güvenli değildir?
Escape_real_string fonksiyonu sadece özel karakterleri veri tabanına gönderildiğinde özel karakter filtrelemesinden geçirilir; ‘ OR 1=’1’ değerini, veri tabanına /’ OR 1/=/’1/’ şeklinde göndererek saldırganın yazdığı sql kodunun, veri tabanında çalışmaması sağlanır. Ancak özel karakter kullanmadan da SQL sorgusu yazıp çalıştırabiliriz. Örnek olarak internet üzerinden alıntıladığım bu sorguya bakabilirsiniz “1+and+2=9+union+select+1,version(),0x4343--%09x” gördüğünüz gibi hiç tırnak işareti ve boşluk bırakmadan da sorgular çalıştırılabiliyor. Tabi UBAS Sistemindeher türlü SELECT, UNİON, DROP, +, “”, --, gibi karakterler sistem tarafından algılanıp daha veri tabanına bağlanmadan sayfadan çıkıpuyarı mesajı verilmesini ve tüm oturumların kapatılmasını sağlıyor. Ancak yine de en yeni ve güvenli olan PDO bağlantılarını kullanmak her zaman daha güvenli olacaktır, PDO da sadece oluşturulan sorgu için hazırlanmış parametre ekleme özelliği ($stmt->bindParam()) bulunduğundan hiç bunlara gerek kalmadan direk güvenli bağlantıyı oluşturmuş oluruz.
1.2 Şifreleri Veri Tabanında Tutmanın En Güvenli Yolu Nedir?
Kullanıcı şifrelerini, şifrelemek için kullanılan en yaygın yöntem MD5 şifrelemesidir. Ancak bu şifreleme yöntemi günümüzde online araçlarla bile çözülebilmektedir. MD5 yerine Algoritma + Salt + MD5(Hashed Password) şifreleme uygulayan PHP fonksiyonu password_Hash(); kullanılmalıdır. Bu şifreleme biçimini kırmak neredeyse imkansızdır çünkü sizin belirlediğiniz algoritmik numaraya göre şifreleme yapar, öyle ki şifreyi çözmek(Doğrulamak) için oluşturulan fonksiyon olan password_verify(); bile şifreyi çözmek yerine veri tabanındaki kayıtlı hali ile karşılaştırarak 1 TRUE veya 0 FALSE değerlerini döndürür, basit bir if/else yardımıyla login sistemlerinde kullanılabilir. $password = password_hash($passal, PASSWORD_DEFAULT, ['cost' => 19]); Kullanıcıdan alınan $password değişkeni password_hash() fonksiyonu ile 19 basamaklı bir algoritmik şifre oluşturuluyor ve veri tabanına şu şekilde kayıt atılıyor(Örenk); ‘$19JgrEKTh64G$8Hj8JgJhFHkFe578’ bu şifreleme oldukça güvenlidir. Örnek if/else kullanımı şu şekilde olabilir;
Login sistemindeki if else’ler ile fonksiyon bir değere eşitlenerek if($password_verify_degeri = = 1){Giriş Doğrulandı}else{Giriş Reddedildi}; şeklinde güvenli şifreleme tamamlanmış oldu. Şifreler dışında diğer kullanıcı verileri için MD5 şifreleme kullanılabilir. Örneğin; Personel mail adresi, müşteri telefonları, adresleri gibi.
1.3 Sistem İçi Yetki Sistemi Nasıl Olmalı ve Kaç Düzeyden Oluşmalıdır?;
UBAS Sisteminden örnek vererek açıklayayım; UBAS’da üç düzey yetki bulanmaktadır, Bunlar sırasıyla en yetkiliden, en yetkisize doğru: R Düzey(RedKey), B Düzey(BlueKey) ve Y Düzey(YellowKey) olarak üçe ayrılmıştır. Her kullanıcının yetki seviyesi kayıt olduğunda boş gelir, kullanıcı kayıt olduktan sonra bir yönetici tarafından atanır. Yetki seviyeleri olmayan kullanıcılar sadece ana sayfaya erişebilir, hiçbir arşive veya veriye erişemez. Bu da kayıt olmadan sisteme bir şekilde girmeyi başarabilen saldırganlar için önlemdir. Yetki seviyeleri şirket içerisinde tüm çalışanların görevli oldukları birim ve araçlara ulaşabilmesini sağlar. Örneğin bir muhasebeci Arşivlere ve Raporlara ulaşabilirken, yetki ve kayıt sistemlerine ulaşamaz ancak bir yöneticinin bütün birim ve araçlara ulaşma imkanı vardır. Sistem yetkileri olabildiğince dikkatli verilmesi ve sayfaya iyi kodlanması gereken önemli bir husustur. Alınacak en önemli önlemleri sizlere anlattım, sırada orta düzey önlemler var bunların çoğu sistemler yapılmadan önce oluşturulması gereken sonradan yapılması zor olan işlemlerdir, ancak yukardaki önlemler alındıysa pek ihtiyaç yoktur.
2. İkinci Düzey Öneme Sahip Güvenlik Önlemleri
2.1 Saldırı Yüzey Alanını Azaltmak:
Veri tabanınızda her sistem için ayrı tablolar oluşturmak yerine, her sistem için ayrı veri tabanları oluşturun ve kullanıcı yetkilerini her sistemin ihtiyacına göre ayrı ayrı belirleyin. Bu sayede A sistemine saldırı düzenlenirse bundan B ve C sistemleri etkilenmeyecektir. Uygulamaya gereksiz özellik eklenmemelidir. Eklenen her özellik yeni bir bağlantı kapısı açtığından risk daha da artar, özellikler olabildiğince işlevsel ve minimal hale getirilmelidir.
2.2 Herkesin Girebildiği Alanları Güçlendirmek:
Sistemin herkes tarafından kullanılabilen bölgeleri örneğin; giriş sayfası, şifre kurtarma sayfası, kayıt sayfası gibi alanlar olabildiğince girdi filtresine tabi tutulmalı. Kullanıcının sadece istenilen verinin girebilmesine müsaade tanınmalı. Veri tabanları sistemden tamamen bağımsız tutulmalı, giriş sayfasında sadece Select sorgusuna izin verilmeli. Bunun için whiteList veya veri tabanı kullanıcısı yetkilendirme kullanılabilir. 2.3 Analiz Sistemi Yapılması: Örneğin UBAS Sistemi içinde kayıt tutan bir sistem var. Ancak dışında yok. Siteye girişin Trafik yoğunluğunu anlık olarak takip edebilecek bir sistem yoğunluğu veya saldırıların arttığı anlarda geliştiricilerin anlık olarak sisteme etkileşimde bulunması sağlanabilir. Verilerin korunmasında ve anlık sistem çökmelerini engellemek için çok işe yarayabilir. 2.4 Yazılımın Güvenlik Gereksinimlerinin Tanımlanması: Güvenlik gereksinimleri, güvenlik risklerinin tanımlanması için ne yapılacağını veya hangi özelliklerin sağlanacağını belirten gereksinimlerdir. Bu gereksinimlerin şirket ve geliştirici tarafından belirlenmesi, yazımının hangi tehditler tarafından hedef alınacağının raporlanması. Özelliklerin bu raporlara göre eklenmesi ve sistemin bu özelliklere göre test edilmesi, sistem halka yayınlanmadan önce büyük önem arz etmektedir. Aşağıdaki şekilde yönlendirmelerin nasıl yapılması gerektiği gösterilmiştir. Şekil Kaynağı: TÜBİTAK BİLGEM;
2.5 Veri Tabanı Sorgularında Döngülerden Kaçınılması:
Sorgularda döngü kullanılması saldırganların lehine sonuçlar doğurabilir. Çok yük isteyen veya kötü amaçla yazılan bir sorguyu döngü içinde çalıştırılması sistem için facia yaratacaktır. Kötü amaçlı sorgulara karşı önlem aldığımızdan dolayı bunu yapmak zor olacaktır, ancak çoklu kullanıcı durumunda döngü sorgular sisteme haddinden fazla yük bindireceğinden sistemde yavaşlamalara ve çökmelere neden olabilir, çok basit ama kötü sonuçlar ortaya çıkarabilecek yanlış kullanımdır. Kullanılması durumunda ise kesinlikle döngü limiti gerçek bir değer olarak belirtilmeli, sonsuz döngüye girmesi engellenmelidir.
2.6 Çıkmak İçin die() fonksiyonundan kaçınılması:
Herhangi bir veri tabanı bağlantı veya sorgu hatasında die() fonksiyonu ile direk çıkmak yerine kayıt(log) tutmak tercih edilmeli, bu sayede hem kullanıcıya nasıl bir hata ile karşılaştığı aktarılabilir hem de yazılımın geliştirilme/onarılma sürecini hızlandıracaktır.
2.7 XSS Saldırılarına Karşı Yeni PHP Sürümlerinin Kullanılması:
XSS Yani (Cross Site Scripting), saldırgan tarafından JavaScript kodlarının istemci yardımı ile çalıştırılmasını sağlar. Yeni PHP sürümlerinde .htaccess dosyasında Options -indexes varsayılan olarak gelmektedir. -indexes komutu kullanıcının sistem dosyalarına erişimini engeller ve 403 hatası verir. Bu her zaman koruma sağlayamayabilir bunun için POST ve GET girdilerine “htmlspecialchars($KullanıcıGirdisi, ENT_QUOTES, 'utf-8');” fonksiyonu kullanılabilir, bu fonksiyon girdilere girilen “<->.;=!” gibi özel karakterleri metin olarak algılamasını sağladığından bir javascript veya herhangi bir html kodu çalıştırmaz.
2.8 Önemli Verileri GET ile Kullanmaktan Kaçınılması:
Önemli kullanıcı verilerinde örneğin şifreler, veriler kesinlikle GET ile URL’ye yansıtılmamalıdır. Sistemlerde POST kullanımı, kişi tarafından takip edilemediğinden çok daha güvenlidir. GET kullanılması illaki zorunlu ise veriler kesinlikle şifrelenmiş olarak URL’ye yansıtılmalıdır.
2.9 Oturum Çerezlerinin Düzgün Ayarlanması:
Çerezler, geliştirici tarafından kullanıcı bilgisayarında tutulun geçici verilerdir. Bu verilerin önemli olanları örneğin; oturum çerezleri, süresiz veya 1 yıl süreli olarak ayarlanmamalı üç ila 5 gün arasında süre belirlenmelidir. Çerezlerin ‘Secure’ etiketi içerdiğinden emin olunmalı, çerez oluştururken JavaScript yerine PHP tercih edilmesi hem XSS saldırılarına karşı, hem de kişi kodları göremediğinden daha güvenli olacaktır.
2.10 PHP Hata Raporlama Eklentisinin Devre Dışı Bırakılması:
PHP Yazılımları otomatik olarak hata raporlama eklentisi açık olarak gelmektedir. Bu sistem yazılım yapılırken, geliştiricinin işine yarar ancak yazılım yayınlandıktan sonra açık olarak bırakılması önemli bir güvenlik zafiyetidir. Saldırgan sisteme girmeden önce sistemi kurcalarken, yaptığı saldırıların hangi hatalar ile karşılaştığını görüntüleyebilirse, bu hatalara göre yeni saldırılarda bulunabilir. “error_reporting(0);” olarak ayarlanırsa, hata raporlama devre dışı kalacak bunun yerine hata anında sadece beyaz bir ekran karşılayacaktır. 2.11 PHP trim() Fonksiyonunun Kullanılması: Trim(); fonksiyonu çok basit ama kullanışlıdır. Girdinin başında ve sonunda boşluk istenmiyorsa kullanılabilir. Trim() fonksiyonu ile girdinin başında ve sonunda bulunan istediğiniz karakterin silinmesini sağlayabiliriz. Örneğin; SQL İnjection saldırılarının çoğunda başta ve sonlarda tek tırnak kullanılmaktadır. Bunu trim fonksiyonu ile trim($girdi,” ’ ”); bu şekilde engelleyebiliriz.
2.11 PHP Sistemdeki Bütün POST ve GET Methodlarının Filtre Edilmesi:
Sistemdeki bütün değişkenlerin teker teker htmlspecialchars(); filtresine geçirmek çok yorucu ve uzun bir iş olacaktır. Bunun yerine array_map(); fonksiyonu ile gelen tüm POST ve GET methodlarını filtreleyebiliriz. POST methodundan sisteme zarar verebilecek verileri filtrelemek için; $_POST = array_map(function($post){ return htmlspecialchars(trim($post)); },$_POST); GET methodundan sisteme zarar verebilecek verileri filtrelemek için; $_GET = array_map(function($get){ return htmlspecialchars(trim($get)); },$_GET); Kullanılabilir. Bu kodları tek bir php dosyasına koyup sistemdeki diğer tüm dosyalara include etmeniz sistem performansını arttıracak ve kod yığılmasının önüne geçecektir.
2.12 Tekrar Eden Kodlar Kullanmaktan Kaçınılması ve Sistem Performansı:
Sistemin güvenliği kadar sistemin düzgün bir performans sağlaması, kolay onarılabilir olması önemlidir hatta bunlar bir güvenlik önlemi olarak bile sayılabilir. Tekrar eden kodların sürekli yazdırılması isteniyorsa döngüler kullanılabilir(Sorgu Hariç Sadece HTML kodu.). Sistem parça parça olarak ayarlanmalıdır, Örneğin; Başlık için, include ‘baslik.php’; Güvenlik kodlarını içeren ve her sayfa için aynı olan kodlar için; include ’guvenlik.php’ şeklinde ayırılmalıdır. Bu şekilde bir yerde sorunla karşılaştığınızda sadece bir dosyada değişiklik yaparak tüm sistemin hatasını çözmüş olursunuz. Ayrıca sistem performansını en iyi şekilde optimize etmek için png dosyalarını jpeg dosyasına çevirebilir veya TinyPng gibi web tabanlı programlar kullanabilir, CSS ve JS dosyalarınızı .min formatına dönüştürebilirsiniz. Pek kullandığım bir yöntem değil anca PHP taglerini kapatmayarak gereksiz boşluk oluşmasını engelleyebilirsiniz. Genellikle HTML ile kullanıldığından bunu önermiyorum. Güvenli olacağım diye de her şeyi şifrelemeyin, gereksiz şifreleme ve çözme işlemleri sistemi çoklu kullanımda olumsuz etkileyecek bir unsurdur.
2.13 Olası Hatalardan Kaçınmak için Kullanıcı Girdilerini Filtrelemek:
PHP 5.2 den sonra gelen filter_var(); fonksiyonu ile kullanıcı girdilerini çok kolay filtreleyebilirsiniz. Bazı filtreleme komutları şu şeklidedir; Email adresi filtrelemesi sağlar ‘FILTER_VALIDATE_EMAIL’, Girdinin integer olup olmadığını doğrular; ‘FILTER_VALIDATE_INT’. Filtreleme için JavaScript kullanılabilir. Ancak PHP daha az kaynak harcadığından tavsiye edilir. 2.14 Kodların Güvenliğinin Sağlanması, Kullanılan Kütüphanelere Dikkat edilmesi: Kodların güvenliğini sağlamak için bir kişi yerine 3-4 kişinin kodları gözden geçirmesi sağlanabilir, birinin görmediği hatayı başkası görebilir. Özellik eklenirken özelliğin ihtiyaç duyduğu kütüphane önce araştırılıp, test ortamında test edilip ondan sonra gerçek yazılımda kullanılmalıdır. Güvenli kütüphaneler kullanmak için CND linkleri tercih edilmelidir. CDN linkleri Google ve Microsoft gibi büyük şirketler tarafından sağlanmaktadır. Ayrıca kütüphanenin sistemde gereksiz yer kaplaması önlenmiş olur. CND linklerinin de 15-20 linkten fazla kullanılması sistemleri yavaşlatabilir. Linklenecek veya indirilecek kütüphane dikkatlice seçilmelidir. Her iki yolun da dengeli kullanılması sistem için daha iyi olacaktır. SON Bu raporda sizlere Şirket içi Web yazılımlarının nasıl daha güvenilir yapılabileceğini anlattım. Okuduğunuz için teşekkür ederim, Güvenli Günler!
Güncellendi: Temmuz 30, 2021