PHP

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.

 

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() veya ctype_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ı: &lt;script&gt;alert(&#039;XSS Saldırısı!&#039;)&lt;/script&gt; Merhaba!
      ?>
      
    • strip_tags(): Belirli HTML ve PHP etiketlerini bir dizgeden kaldırır. Ancak bu, saldırganların farklı kodlama teknikleri kullanmasını engellemez ve htmlspecialchars() 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=Lax veya SameSite=Strict ayarları 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çin HttpOnly (JavaScript erişimini engeller) ve Secure (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_errors ayarını Off konumuna 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: DENY veya SAMEORIGIN: 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 audit gibi 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.

Emre NACAR

Merhaba! Ben Emre Nacar, full stack web developer olarak yaklaşık 10 yıldır kurumsal web siteleri, e-ticaret siteleri ve firmalara özel web tabanlı uygulamalar geliştiriyorum.2013 yılından itibaren yurtiçi veya yurtdışı olarak 200 den fazla projede web tabanlı yazılım geliştirici olarak yer almış, kodlama, veritabanı geliştirme, arayüz tasarımı gibi bir çok alanda görev almış bulunmaktayım. KKTC ve İstanbul gibi farklı şehirlerde Junior Developer, Senior Developer, Proje Yöneticisi olarak çalıştıktan sonra son olarak Gaziantep’de Yazılım Uzmanı olarak çalışmalarımı sürdürmekteyim.

İlgili Makaleler

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Göz Atın
Kapalı
Başa dön tuşu