Web geliştirme dünyasında harika, dinamik ve işlevsel bir PHP uygulaması kodlamak madalyonun sadece bir yüzüdür. Geliştirdiğiniz uygulama internete açıldığı andan itibaren, açıklar bulmaya çalışan botların ve kötü niyetli kişilerin hedefi haline gelir. PHP dilinin internetteki web sitelerinin yaklaşık %70’inden fazlasına güç vermesi, onu bilgisayar korsanları (hackerlar) için oldukça cazip bir hedef yapmaktadır.
Ancak PHP’nin kendisi güvensiz değildir; güvenlik açıkları çoğunlukla geliştiricilerin kod yazarken yaptıkları hatalardan, özellikle de kullanıcıdan gelen verileri doğru şekilde kontrol etmemelerinden (sanitize etmemelerinden) kaynaklanır. Bu rehberde, PHP projelerinizde karşılaşabileceğiniz en yaygın güvenlik tehditlerini ve bu tehditlere karşı alabileceğiniz modern önlemleri adım adım ve örneklerle öğreneceğiz.
1. Altın Kural: Kullanıcı Verisine Asla Güvenmeyin!
Web güvenliğinin temel kuralı şudur: Kullanıcıdan gelen (formlar, URL parametreleri, çerezler veya API çağrıları yoluyla) hiçbir veriye asla %100 güvenmemelisiniz. PHP uygulamalarındaki zafiyetlerin büyük bir çoğunluğu, “temizlenmemiş” (unsanitized) verilerin sistemde doğrudan kullanılmasıyla ortaya çıkar.
Bu tehlikeyi önlemek için iki temel kalkanımız vardır:
- Doğrulama (Validation): Gelen verinin beklediğimiz formatta olup olmadığını kontrol etmektir (örneğin; girilen metin gerçekten bir e-posta adresi mi?). PHP’deki
filter_var()fonksiyonu bu iş için mükemmeldir. Ayrıca sadece izin verilen değerlerin kabul edildiği “beyaz liste” (allowlist) yöntemi kullanılmalıdır. - Temizleme (Sanitization / Escaping): Verinin içindeki zararlı olabilecek HTML veya PHP kodlarını, sisteme zarar veremeyecek güvenli metinlere dönüştürmektir.
2. SQL Enjeksiyonu (SQL Injection – SQLi) ve PDO Kullanımı
SQL Enjeksiyonu, kötü niyetli kişilerin form alanlarına özel veritabanı (SQL) komutları yazarak veritabanınıza sızdığı, veri çalabildiği veya silebildiği en tehlikeli saldırı türlerinden biridir.
Örneğin, kullanıcı adı alanına ' OR '1'='1' -- gibi bir metin giren bir saldırgan, yazdığınız basit bir SQL sorgusunu kandırarak hiçbir şifre bilmeden yönetici paneline giriş yapabilir.
Nasıl Korunuruz? Asla kullanıcıdan gelen değişkenleri SQL sorgularınızın içine doğrudan (metin birleştirme ile) yazmayın. Bunun yerine her zaman Hazırlanmış İfadeler (Prepared Statements) kullanın. Hazırlanmış ifadeler, SQL komutunun yapısı ile kullanıcının girdiği veriyi birbirinden ayırır.
<?php
// GÜVENSİZ KULLANIM (Asla yapmayın!)
// $kullanici_adi doğrudan sorguya ekleniyor, SQL Injection'a açık!
// $sql = "SELECT * FROM kullanicilar WHERE username = '$kullanici_adi'";
// GÜVENLİ KULLANIM (PDO ile Prepared Statements)
$sql = "SELECT * FROM kullanicilar WHERE username = :username";
$stmt = $pdo->prepare($sql);
// Kullanıcı verisi güvenli bir parametre olarak sorguya bağlanıyor
$stmt->execute(['username' => $_POST['username']]);
$kullanici = $stmt->fetch();
?>
3. Cross-Site Scripting (XSS) Saldırıları
XSS (Siteler Arası Komut Dosyası Çalıştırma), bir saldırganın web sitenize zararlı JavaScript kodları enjekte etmesi ve bu kodların diğer ziyaretçilerin tarayıcısında çalışmasını sağlamasıdır. Bu kodlar aracılığıyla kullanıcıların oturum çerezleri (cookies) çalınabilir ve hesapları ele geçirilebilir.
XSS saldırıları kabaca üçe ayrılır: Zararlı kodun veritabanına kaydedilip herkese gösterildiği Stored XSS, linklere gizlendiği Reflected XSS ve doğrudan tarayıcı DOM yapısına müdahale eden DOM-based XSS.
Nasıl Korunuruz? Kullanıcıdan gelen bir veriyi HTML sayfası içerisinde ekrana yazdırırken (echo ederken) mutlaka Çıktıyı Kaçırma (Output Escaping) işlemi yapmalısınız. PHP’deki htmlspecialchars() fonksiyonu, < ve > gibi HTML etiketlerini oluşturan karakterleri, tarayıcının kod olarak algılamayacağı güvenli sembollere (< ve >) dönüştürür.
<?php
$kullanici_yorumu = "<script>alert('Siteni hackledim!');</script> Harika bir yazı.";
// GÜVENSİZ: JavaScript kodu ekranda anında çalışır
// echo $kullanici_yorumu;
// GÜVENLİ: Sadece düz metin olarak ekranda görünür
echo htmlspecialchars($kullanici_yorumu, ENT_QUOTES, 'UTF-8');
?>
Ayrıca, modern uygulamalarda hangi betiklerin çalışabileceğini sınırlayan İçerik Güvenlik Politikası (CSP) başlıklarının (headers) kullanılması da XSS riskini büyük ölçüde azaltır.
4. Cross-Site Request Forgery (CSRF)
CSRF, bir yöneticinin veya kullanıcının, kendi isteği dışında (örneğin sahte bir linke tıklatılarak) arka planda işlem yapmaya (şifre değiştirme, para transferi vb.) zorlandığı bir saldırı türüdür.
Nasıl Korunuruz? Bu tür saldırıları engellemenin en iyi yolu formlarınıza tek kullanımlık, rastgele oluşturulmuş CSRF Token’ları (Jetonları) eklemektir. Kullanıcı oturum açtığında bir token üretilir ve kullanıcının oturumuna ($_SESSION) kaydedilir. Her form gönderiminde bu token da gönderilir; eğer formdan gelen token ile oturumdaki token eşleşmezse işlem reddedilir.
5. Parolaları Güvenli Saklamak (Password Hashing)
Kullanıcıların parolalarını veritabanında düz metin (plain text) olarak veya MD5, SHA1 gibi artık kolayca kırılabilen eski şifreleme yöntemleriyle saklamak çok büyük bir güvenlik ihlalidir.
Nasıl Korunuruz? PHP, parolaları güvenle kriptolamak (hash’lemek) için özel bir fonksiyona sahiptir: password_hash(). Bu fonksiyon, arka planda en modern ve güvenli algoritmaları (Bcrypt veya Argon2) kullanır ve şifrelere otomatik olarak karmaşıklık (salt) ekler.
<?php
// Şifreyi Kaydederken:
$guvenli_sifre = password_hash($_POST['password'], PASSWORD_DEFAULT);
// Çıktı örneği: $2y$10$wT8... (Bu değer veritabanına kaydedilir)
// Kullanıcı Giriş Yaparken Kontrol Etme:
if (password_verify($_POST['password'], $veritabanindaki_hash)) {
echo "Giriş başarılı!";
} else {
echo "Hatalı şifre.";
}
?>
Kendi şifreleme mantığınızı yazmaya çalışmaktan kaçının; uzmanlar tarafından geliştirilmiş bu yerleşik fonksiyonlara güvenin.
6. Oturum (Session) ve Çerez Güvenliği
Oturum çalınmalarını önlemek için PHP’nin $_SESSION mekanizmasını doğru yapılandırmalısınız.
- Kullanıcının tarayıcısındaki oturum kimliğini (Session ID) korumak için
php.inidosyanızdasession.cookie_httponly = 1ayarını yapın; bu, JavaScript’in oturum çerezlerine erişmesini engeller. - Eğer siteniz SSL (HTTPS) kullanıyorsa
session.cookie_secure = 1yaparak çerezlerin sadece şifreli bağlantılarda taşınmasını sağlayın. - Kullanıcı giriş (login) yaptığında veya şifre değiştirdiğinde, oturum sabitlenmesi (session fixation) saldırılarını engellemek için
session_regenerate_id(true)fonksiyonunu kullanarak yeni bir oturum kimliği üretin.
7. Güvenli Dosya Yükleme (File Upload)
Kullanıcılara sitenize profil fotoğrafı veya belge yükleme izni verdiğinizde, oldukça dikkatli olmalısınız. Bir saldırgan görüntü dosyası gibi görünen bir .jpg dosyası içine zararlı PHP kodları gizleyip yükleyebilir.
Nasıl Korunuruz?
- Yüklenen dosyanın sadece uzantısına (
.jpg,.png) güvenmeyin. Gerçek MIME türünü ve içeriğini kontrol edin (örneğinfinfokullanarak). - Kullanıcıların yüklediği dosyaları asla web kök dizininde (public_html/htdocs) doğrudan çalıştırılabilir şekilde saklamayın. Dışarıdan URL ile doğrudan erişilemeyen daha üst bir klasörde saklayın.
- Dosya yüklenen klasörlerin PHP kodu çalıştırma (execution) yetkilerini sunucu yapılandırmasından (Apache/Nginx) iptal edin.
8. Uzaktan Kod Çalıştırma (RCE) ve php.ini Ayarları
Uzaktan Kod Çalıştırma (RCE), bir saldırganın sunucunuzda kendi komutlarını çalıştırmasına izin veren ve uygulamanın tamamen ele geçirilmesiyle sonuçlanan ölümcül zafiyetlerdir. RCE açıklarından korunmak için kullanıcı girdilerini eval(), exec(), system() gibi fonksiyonlara asla doğrudan aktarmamalısınız.
Ayrıca sunucunuzun php.ini yapılandırmasını güvenli hale getirmek kritik bir adımdır:
display_errors = Off: Geliştirme (development) yaparken hataları görmek iyidir, ancak yayındaki (production) sitenizde hata gösterimini mutlaka kapatın. Aksi takdirde, veritabanı yolları veya dosya yapılarınız saldırganlara ifşa olur.log_errors = On: Hataları ekrana basmak yerine her zaman bir log dosyasına kaydedin.allow_url_fopen = Off: PHP’nin dış URL’leri dosyalar gibi okumasını engeller ve RFI (Remote File Inclusion – Uzaktan Dosya Dahil Etme) açıklarına karşı koruma sağlar.- Gerekmiyorsa
disable_functionsyönergesini kullanarakexec(),passthru(),shell_exec()gibi sistem komutu çalıştıran fonksiyonları tamamen kapatın.
Sonuç
PHP projelerinde güvenliği sağlamak tek seferlik bir ayar değil, uygulamanın tasarım aşamasından başlayarak devam eden sürekli bir süreçtir. Kullanıcıdan gelen veriyi her zaman doğrulayıp temizleyerek, veritabanı bağlantılarınızda PDO (Hazırlanmış İfadeler) kullanarak, parolaları doğru hash’leyerek ve htmlspecialchars() ile çıktılarınızı kaçırarak en yaygın web saldırılarından büyük ölçüde korunabilirsiniz. Unutmayın, güvenlik için baştan yatırım yapmak (önlem almak), bir ihlal yaşandıktan sonra oluşan itibar ve veri kaybıyla uğraşmaktan her zaman daha az maliyetlidir.






