PHP ile Güvenli Kod Yazma Pratikleri
PHP ile Güvenli Kod Yazma Pratikleri: SQL Enjeksiyonu, XSS ve Diğer Saldırılara Karşı Korunma

PHP ile güvenli kod yazma, günümüz web uygulamaları için hayati bir gerekliliktir. Web uygulamaları yaygınlaştıkça, güvenlik açıkları da siber saldırganların hedefi haline geliyor. PHP, web uygulaması geliştiricilerinin popüler bir dili olsa da, doğru güvenlik pratikleri uygulanmadığında sitenizi ve kullanıcı verilerinizi ciddi risk altına sokabilir. SQL enjeksiyonu, XSS (Cross-Site Scripting) ve CSRF (Cross-Site Request Forgery) gibi saldırılar, geliştiricilerin en sık karşılaştığı tehditler arasında. Peki, bu saldırılara karşı nasıl önlemler alınır? Bu kapsamlı rehberde, web uygulamalarınızı korumanız için temel güvenlik prensiplerini ve pratiklerini detaylıca inceleyeceğiz.
İçindekiler
- 1. SQL Enjeksiyonu: Veritabanınızı Korumanın Anahtarı
- 2. XSS (Cross-Site Scripting): Kullanıcı Verilerini Korumak
- 3. CSRF (Cross-Site Request Forgery): İstem Dışı İsteklere Karşı Savunma
- 4. Güvenli Kimlik Doğrulama ve Oturum Yönetimi
- 5. Dosya Yükleme Güvenliği
- 6. Hata Yönetimi ve Loglama
- 7. Güvenlik Başlıkları (Security Headers)
- 8. Güvenlik Güncellemeleri ve Bağımlılıklar
1. SQL Enjeksiyonu: Veritabanınızı Korumanın Anahtarı
SQL enjeksiyonu, saldırganların web uygulamanızın veritabanına yetkisiz erişim sağlamak veya veritabanını manipüle etmek amacıyla SQL sorgularına kötü niyetli kod parçacıkları eklemesiyle gerçekleşen bir saldırı türüdür. Bu, kullanıcı girişi gibi alanlarda yeterli doğrulama yapılmadığında ortaya çıkar.
Nasıl Korunulur?
- Hazırlanmış İfadeler (Prepared Statements) ve Parametreli Sorgular: SQL enjeksiyonuna karşı en etkili savunma yöntemi budur. Kullanıcıdan alınan veriler, doğrudan SQL sorgusuna eklenmek yerine, sorgu şablonu oluşturulduktan sonra parametre olarak bağlanır. Bu, verinin bir kod parçası olarak değil, yalnızca bir değer olarak yorumlanmasını sağlar.PDO (PHP Data Objects) ile Örnek:
<?php $username = $_POST['username']; $password = $_POST['password']; try { $dsn = 'mysql:host=localhost;dbname=mydb'; $user = 'myuser'; $pass = 'mypass'; $pdo = new PDO($dsn, $user, $pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password"); $stmt->bindParam(':username', $username); $stmt->bindParam(':password', $password); $stmt->execute(); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { echo "Giriş Başarılı!"; } else { echo "Kullanıcı adı veya şifre yanlış."; } } catch (PDOException $e) { echo "Veritabanı hatası: " . $e->getMessage(); } ?>MySQLi ile Örnek:
<?php $username = $_POST['username']; $password = $_POST['password']; $mysqli = new mysqli("localhost", "myuser", "mypass", "mydb"); if ($mysqli->connect_error) { die("Bağlantı hatası: " . $mysqli->connect_error); } $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->bind_param("ss", $username, $password); // "ss" string parametreler için $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows > 0) { echo "Giriş Başarılı!"; } else { echo "Kullanıcı adı veya şifre yanlış."; } $stmt->close(); $mysqli->close(); ?> - Giriş Doğrulaması (Input Validation): Her zaman kullanıcı girişini beklenen formatta olup olmadığını kontrol edin. Örneğin, bir e-posta adresi bekleniyorsa, formatın e-posta adresine uygun olup olmadığını
filter_var()fonksiyonu ile doğrulayın. Sayısal bir değer bekleniyorsa,is_numeric()veyactype_digit()gibi fonksiyonlar kullanın. - Hata Mesajlarını Kısıtlayın: Uygulamanızın canlı ortamda detaylı veritabanı hata mesajları göstermediğinden emin olun. Bu tür mesajlar saldırganlara veritabanı yapısı hakkında ipuçları verebilir. Üretim ortamında genel bir hata mesajı (örn. “Bir sorun oluştu.”) gösterin ve detayları sunucu loglarına kaydedin.
2. XSS (Cross-Site Scripting): Kullanıcı Verilerini Korumak
XSS, saldırganın kötü niyetli istemci tarafı betikleri (genellikle JavaScript) web sayfalarına enjekte etmesiyle gerçekleşir. Bu betikler, diğer kullanıcıların tarayıcılarında çalışarak oturum çerezlerini çalabilir, hassas bilgilere erişebilir veya sayfayı manipüle edebilir. PHP güvenlik pratikleri arasında XSS’e karşı korunma hayati önem taşır.
Nasıl Korunulur?
- Tüm Kullanıcı Girişlerini Filtreleme ve Kaçırma (Escaping): Kullanıcıdan alınan ve HTML çıktısı olarak gösterilecek tüm verileri uygun şekilde kaçırmak (escape) çok önemlidir. Bu, verinin HTML etiketi olarak yorumlanmasını engeller.
htmlspecialchars(): Bu fonksiyon, HTML özel karakterlerini (<,>,&,",') HTML varlıklarına dönüştürür. Çoğu XSS saldırısına karşı etkilidir.<?php $comment = "<script>alert('XSS Saldırısı!')</script> Merhaba!"; echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8'); // Çıktı: <script>alert('XSS Saldırısı!')</script> Merhaba! ?>strip_tags(): Belirli HTML ve PHP etiketlerini bir dizgeden kaldırır. Ancak bu, saldırganların farklı kodlama teknikleri kullanmasını engellemez vehtmlspecialchars()kadar güvenli değildir.<?php $comment = "<script>alert('XSS Saldırısı!')</script> Merhaba!"; echo strip_tags($comment); // Çıktı: alert('XSS Saldırısı!') Merhaba! ?>
- İçerik Güvenlik Politikası (Content Security Policy – CSP): Sunucunuzda bir CSP başlığı tanımlayarak, tarayıcıya hangi kaynaklardan (betikler, stil sayfaları, görseller vb.) içerik yükleyebileceğini belirtirsiniz. Bu, kötü niyetli betiklerin yüklenmesini engeller.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; - Kullanıcıdan Gelen URL’leri Doğrulama: Eğer kullanıcıdan URL alıp bunu bağlantı olarak kullanıyorsanız,
filter_var($url, FILTER_VALIDATE_URL)ile URL’nin geçerli bir formatta olduğunu doğrulayın. Ayrıca, “javascript:” gibi tehlikeli protokollerin kullanımını engelleyin.
3. CSRF (Cross-Site Request Forgery): İstem Dışı İsteklere Karşı Savunma
CSRF, saldırganın kullanıcının bilgisi veya izni olmadan, kullanıcının oturum açmış olduğu bir web uygulamasında istenmeyen bir eylemi gerçekleştirmesini sağlamasıdır. Örneğin, kullanıcının banka hesabından para transferi yapması gibi. PHP ile güvenli kod yazarken CSRF korumasını mutlaka uygulayın.
Nasıl Korunulur?
- CSRF Token Kullanımı: Bu, CSRF saldırılarına karşı en yaygın ve etkili savunma yöntemidir. Her kritik form veya istek için benzersiz ve rastgele bir token (belirteç) oluşturulur. Bu token hem kullanıcının oturumunda saklanır hem de formun gizli bir alanına yerleştirilir. Sunucu, isteği işlerken formdan gelen token ile oturumdaki token’ı karşılaştırır. Eşleşmezse istek reddedilir.Örnek Uygulama:
<?php // Formu gösterirken token oluşturma session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } $csrf_token = $_SESSION['csrf_token']; ?> <form action="process.php" method="POST"> <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token); ?>"> <label for="amount">Miktar:</label> <input type="text" id="amount" name="amount"><br><br> <input type="submit" value="Transfer Et"> </form> <?php // process.php dosyasında token doğrulama session_start(); if (!empty($_POST['csrf_token']) && hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { // Token geçerli, işlemi yap echo "İşlem başarıyla tamamlandı."; // Güvenlik için tokenı yeniden oluştur (her istekte değişmesi daha güvenlidir) $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } else { // Token geçersiz veya eksik, işlemi reddet die("CSRF saldırısı tespit edildi veya geçersiz istek!"); } ?> - SameSite Çerezleri: Tarayıcılara çerezlerin hangi durumlarda üçüncü taraf sitelere gönderileceğini belirtir.
SameSite=LaxveyaSameSite=Strictayarları CSRF saldırılarına karşı koruma sağlar.
4. Güvenli Kimlik Doğrulama ve Oturum Yönetimi
Kullanıcıların kimliklerini doğrulama ve oturumlarını yönetme şekliniz de güvenlik açısından kritiktir. PHP güvenlik pratikleri bu alanda da büyük önem taşır.
- Şifreleri Hashleme: Şifreleri asla düz metin olarak veritabanında saklamayın. Daima güçlü, tek yönlü hash algoritmaları kullanın (örn.
password_hash()fonksiyonu).password_verify()fonksiyonu ile şifreleri doğrulayın.<?php // Şifre hashleme $password = 'mySuperSecretPassword'; $hashedPassword = password_hash($password, PASSWORD_DEFAULT); echo $hashedPassword; // Şifre doğrulama $inputPassword = 'mySuperSecretPassword'; if (password_verify($inputPassword, $hashedPassword)) { echo "Şifre doğru!"; } else { echo "Şifre yanlış!"; } ?> - Oturum Kimliği Yönetimi:
- Oturum kimliklerini URL’de veya GET parametrelerinde asla geçirmeyin.
- Oturum kimliğini sabit tutmak yerine, kullanıcı her giriş yaptığında veya belirli aralıklarla oturum kimliğini yeniden oluşturun (
session_regenerate_id()). session_set_cookie_params()ile oturum çerezleri içinHttpOnly(JavaScript erişimini engeller) veSecure(sadece HTTPS üzerinden gönderilir) bayraklarını ayarlayın.
- Kaba Kuvvet (Brute Force) Koruması: Başarısız giriş denemeleri için bir limit belirleyin ve belirli bir süre boyunca IP adresini engelleyin veya CAPTCHA gibi ek doğrulamalar kullanın.
5. Dosya Yükleme Güvenliği
Kullanıcıların dosya yüklemesine izin veren uygulamalarda ciddi güvenlik açıkları oluşabilir. Bu da PHP ile güvenli kod yazmanın önemli bir parçasıdır.
- Dosya Türü Doğrulaması: Yalnızca izin verilen dosya türlerinin (MIME tipi kontrolü ile) yüklenmesine izin verin. Dosya uzantısını kontrol etmek yeterli değildir, çünkü uzantılar kolayca manipüle edilebilir.
- Dosya Boyutu Sınırlaması: Yüklenen dosyaların boyutunu sınırlayın.
- Zararlı Kod Taraması: Yüklenen görsellerde veya diğer dosyalarda gizlenmiş zararlı kod olup olmadığını taramak için sunucu tarafı bir antivirüs veya güvenlik yazılımı kullanın.
- Yükleme Dizinini Uygulama Dışında Tutma: Yüklenen dosyaları web kök dizininin dışındaki bir dizine kaydedin ve onlara doğrudan HTTP erişimi olmamasını sağlayın. Eğer erişmeleri gerekiyorsa, PHP üzerinden güvenli bir şekilde sunun.
6. Hata Yönetimi ve Loglama
- Detaylı Hata Mesajlarından Kaçının: Üretim ortamında
display_errorsayarınıOffkonumuna getirin. Detaylı hata mesajları saldırganlara sunucunuz veya uygulamanız hakkında hassas bilgiler verebilir. - Hata Loglarını Kullanın: Tüm hataları bir dosyaya veya merkezi bir loglama sistemine kaydedin (
error_log()). Bu loglar, güvenlik sorunlarını veya şüpheli aktiviteleri izlemenize yardımcı olur.
7. Güvenlik Başlıkları (Security Headers)
HTTP güvenlik başlıkları, tarayıcı tabanlı saldırıları önlemeye yardımcı olur.
X-Content-Type-Options: nosniff: Tarayıcıların MIME türlerini tahmin etmesini engeller.X-Frame-Options: DENYveyaSAMEORIGIN: Sitenizin başka siteler tarafından iFrame içinde açılmasını engelleyerek Clickjacking saldırılarına karşı koruma sağlar.Strict-Transport-Security (HSTS): Tarayıcıları sitenize her zaman HTTPS üzerinden bağlanmaya zorlar.Referrer-Policy: Referans bilgilerinin ne zaman ve nasıl gönderileceğini kontrol eder.
8. Güvenlik Güncellemeleri ve Bağımlılıklar
- PHP Sürümü: Her zaman PHP’nin en son kararlı sürümünü kullanın. Yeni sürümler genellikle performans iyileştirmelerinin yanı sıra önemli güvenlik yamaları içerir.
- Framework’ler ve Kütüphaneler: Kullandığınız tüm PHP framework‘lerini (Laravel, Symfony vb.) ve üçüncü taraf kütüphanelerini düzenli olarak güncelleyin. Bu yazılımların bilinen güvenlik açıkları genellikle güncellemelerle kapatılır.
- Bağımlılık Yöneticisi Kullanımı: Composer gibi bir bağımlılık yöneticisi kullanıyorsanız,
composer auditgibi komutlarla bilinen güvenlik açıklarını tarayabilirsiniz.
PHP ile güvenli kod yazmak, sürekli öğrenme ve dikkat gerektiren bir süreçtir. Yukarıda bahsedilen PHP güvenlik pratikleri, SQL enjeksiyonu, XSS, CSRF gibi yaygın saldırılara karşı uygulamanızı büyük ölçüde koruyacaktır. Unutmayın, güvenlik sadece bir kez yapılan bir şey değildir; uygulamanız geliştikçe, yeni teknolojiler çıktıkça ve tehditler evrildikçe sürekli olarak gözden geçirilmeli ve güncellenmelidir. Her zaman “kullanıcıdan gelen hiçbir şeye güvenme” prensibiyle hareket edin ve tüm girişleri doğrulayın, kaçırın ve temizleyin. Güvenli bir web uygulaması, hem sizin hem de kullanıcılarınızın dijital dünyada huzur içinde hareket etmesini sağlar.



