Yazılarımız

OfisData

PHP İLE GÜVENLİ FORM İŞLEMEK VE İNJECTİON ÖNLEMEK

Web uygulamalarında formlar, kullanıcıyla temas eden en kritik yüzeylerden biridir. Bir “iletişim” ya da “kayıt” formu gibi basit görünen alanlar bile, zayıf doğrulama ve yanlış veritabanı kullanımıyla hızlıca güvenlik açığına dönüşebilir.

Bu yazıda PHP güvenli form işleme yaklaşımını adım adım ele alacağız. Hedef; veriyi doğru doğrulamak, güvenli şekilde saklamak ve çıktıyı güvenli üretmek. Böylece SQL injection, XSS ve CSRF gibi yaygın tehditleri pratik yöntemlerle azaltabileceksiniz.

İçerik boyunca gerçekçi örnekler, kontrol listeleri ve tekrar kullanılabilir küçük parçalar göreceksiniz. Ekibinizde standartlaştırabileceğiniz bir “güvenli form hattı” kurmaya odaklanacağız.

Güvenli form akışını planlayan ekip, doğrulama kuralları ve veritabanı katmanını aynı ekranda değerlendiriyor

PHP güvenli form işleme yaklaşımını kurgulamak

Güvenli form işlemek, tek bir “filtre” eklemekten ibaret değildir. Sağlam bir yaklaşım; giriş doğrulama, güvenli veri erişimi, güvenli çıktı üretme ve istek bütünlüğünü korumayı birlikte ele alır.

Tehdit yüzeyini form alanlarına göre haritalamak

Hangi alanlar serbest metin kabul ediyor, hangileri sayısal, hangileri seçim listesi? Bu ayrımı netleştirmek; doğrulama kurallarını alan bazında tanımlamakla başlar. Örneğin “ad” alanı belirli karakter setine izin verirken, “yaş” alanı yalnızca sayı aralığı kabul etmelidir.

Sunucu tarafı doğrulama katmanı tasarlamak

İstemci tarafı kontroller kullanıcı deneyimini iyileştirir; ancak güvenlik için yeterli değildir. Sunucuda, gelen her alanı “beklenen tip” ve “beklenen format” ile doğrulamak gerekir. Bu katman; form doğrulama kurallarını tek noktada toplamakla sürdürülebilir hale gelir.

Input validation ile veri kalitesini güvenceye almak

Input validation, veriyi “temizlemekten” çok “kabul etmek” üzerine kurulur. Kabul edeceğiniz formatı tanımlayıp bunun dışındaki her şeyi reddetmek, hem güvenliği hem veri kalitesini artırır.

Whitelist doğrulama ile kabul edilebilir formatı tanımlamak

Örnek olarak e-posta, telefon ve sayısal alanlar için whitelist doğrulama kullanın. Bu, “yasaklı karakterleri çıkarma” yaklaşımına göre daha güvenilirdir. Çünkü saldırganın yeni bir varyasyonla kuralı aşma olasılığını azaltır.

Filtreleme ile normalize etmek ve hata mesajlarını yönetmek

Doğrulama başarısız olduğunda kullanıcıya anlaşılır, kısa ve yönlendirici mesajlar vermek gerekir. Aynı zamanda log tarafında daha ayrıntılı hata bağlamı tutarak ekip içi tanı koymayı hızlandırabilirsiniz. Hata mesajlarında hassas detay paylaşmamak önemlidir.

Prepared statement ile SQL injection riskini azaltmak

Veritabanına yazılan veya veritabanından okunan her değer için prepared statement kullanmak, SQL injection’a karşı temel savunmadır. “String birleştirme” ile sorgu üretmek, en küçük kaçırmada ciddi riske dönüşebilir.

PDO ile parametre bağlayarak güvenli sorgu çalıştırmak

Aşağıdaki örnek, tipik bir kayıt formundan gelen veriyi doğrulayıp PDO ile güvenli biçimde ekler. Bu örnekte hem doğrulama hem de güvenli veritabanı yazımı birlikte ele alınır.

<?php
declare(strict_types=1);

session_start();

function post(string $key): string {
  return isset($_POST[$key]) ? trim((string)$_POST[$key]) : '';
}

$errors = [];
$name  = post('name');
$email = post('email');

if ($name === '' || mb_strlen($name) < 2 || mb_strlen($name) > 80) {
  $errors['name'] = 'Ad alanı 2-80 karakter olmalı.';
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  $errors['email'] = 'E-posta formatı geçersiz.';
}

if (!hash_equals($_SESSION['csrf'] ?? '', post('csrf'))) {
  $errors['csrf'] = 'İstek doğrulanamadı, tekrar deneyin.';
}

if ($errors) {
  // Hataları kullanıcıya döndürürken detay sızdırmayın
  http_response_code(422);
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(['errors' => $errors], JSON_UNESCAPED_UNICODE);
  exit;
}

// PDO bağlantısı (örnek)
$pdo = new PDO(
  'mysql:host=localhost;dbname=app;charset=utf8mb4',
  'db_user',
  'db_pass',
  [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  ]
);

$stmt = $pdo->prepare('INSERT INTO contacts (name, email, created_at) VALUES (:name, :email, NOW())');
$stmt->execute([
  ':name'  => $name,
  ':email' => $email,
]);

echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
?>

Sorgu birleştirmeyi bırakmak ve loglamayı düzenlemek

Parametre bağlama kullanıldığında, saldırganın sorgu yapısını bozması zorlaşır. Ayrıca hata durumunda kullanıcıya “veritabanı hatası” gibi genel bir mesaj dönüp, ayrıntıyı log tarafında tutmak daha güvenlidir. Böylece operasyon ekibi için iz sürmek kolaylaşırken, dışarıya bilgi sızma riski azalır.

Kod editöründe PDO prepare ve execute adımları, parametre isimleriyle birlikte okunabilir biçimde uygulanıyor

CSRF token ile istek bütünlüğünü korumak

CSRF, kullanıcının oturumu açıkken onun adına istek yaptırmayı hedefler. Özellikle form gönderen sayfalarda, CSRF token kullanmak ve token’ı sunucuda doğrulamak kritik bir adımdır.

Token üretmek ve form içine güvenli eklemek

Token üretimi için kriptografik olarak güvenli rastgelelik kullanın. Token’ı oturumda saklayıp form içine gizli alanla ekleyin. Bu token, her form gönderiminde sunucu tarafında karşılaştırılmalıdır.

Token doğrulamak ve yeniden üretmek

Token doğrulaması başarısız olursa isteği reddedin. Kritik işlemlerde token’ı periyodik olarak yenilemek ve aynı token’ın uzun süre kullanılmasını engellemek de faydalıdır. Bu yaklaşım, istek bütünlüğünü artırır.

XSS riskini azaltmak için output escaping uygulamak

XSS çoğu zaman “girişte temizleme” sanılır; oysa asıl kritik adım, veriyi ekrana basarken doğru bağlama göre kaçışlamakla başlar. HTML içinde gösterilecek metin ile HTML attribute içinde gösterilecek metin aynı şekilde ele alınmamalıdır.

htmlspecialchars ile güvenli çıktı üretmek

Aşağıdaki örnek, formdan gelen bir değeri ekranda güvenli biçimde göstermeyi amaçlar. Burada odak; veriyi “ne amaçla” çıktıladığınıza göre doğru kaçışlama yapmaktır.

<?php
declare(strict_types=1);

function e(string $value): string {
  return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

$name = $_GET['name'] ?? '';
?>

<p>Merhaba, <strong><?= e($name) ?></strong>!</p>
<p>Bu sayfada gösterilen tüm kullanıcı girdileri, ekrana basmadan önce kaçışlanır.</p>

Bağlama göre kaçışlamak ve şablonları disipline etmek

HTML gövdesi, attribute, URL parametresi veya JavaScript bağlamı farklı kaçışlama gerektirir. Basit projelerde bile “çıktı yardımcı fonksiyonu” kullanmak, ekip içinde standardı korur. Ayrıca şablonlarda çıplak kullanıcı girdisi göstermemek, review süreçlerini hızlandırır.

Güvenlik kontrol listesinde doğrulama, CSRF, prepared statement ve çıktı kaçışlama maddeleri işaretlenmiş durumda

Güvenli form akışı için pratik kontrol listesi oluşturmak

Uygulamada hız kazanmak için her formda tekrar eden bir kontrol listesi kullanabilirsiniz. Aşağıdaki adımlar, form doğrulama ve güvenli veri akışı için temel bir çerçeve sunar.

Kontrol listesini ekiple standartlaştırmak

  • Her alan için beklenen tip ve formatı tanımlamak
  • Sunucu tarafında input validation uygulamak
  • Veritabanı işlemlerinde prepared statement kullanmak
  • CSRF token üretmek, saklamak ve doğrulamak
  • Çıktıda bağlama göre output escaping yapmak
  • Hata mesajlarında hassas detay paylaşmamak

Geliştirme sürecine test ve gözden geçirme eklemek

Formlar için otomatik testler yazmak, regresyon riskini düşürür. Özellikle doğrulama kuralları değiştikçe, beklenmeyen veri kabulü veya reddi yaşanabilir. Code review sırasında “sorgu birleştirme var mı”, “çıktıda kaçışlama var mı” gibi maddeler net kontrol noktalarıdır.

Performans ve kullanıcı deneyimi için güvenliği desteklemek

Güvenlik önlemleri kullanıcı deneyimini bozmak zorunda değildir. Doğru tasarlandığında, güvenlik hem hız hem de kalite açısından fayda sağlar. Örneğin sunucuda doğrulama şarttır; ancak istemci tarafı uyarılar kullanıcıyı daha hızlı yönlendirir.

Rate limiting ve bot trafiğini yönetmek

Özellikle giriş, kayıt ve iletişim formlarında kaba kuvvet veya spam trafiğiyle karşılaşabilirsiniz. Basit rate limiting, CAPTCHA veya davranışsal kontroller; kaynak tüketimini azaltır. Bu katmanlar, doğrulama ve veritabanı katmanına ulaşan kötü niyetli trafiği düşürür.

Gözlemlenebilirlik ile anomaliyi erken yakalamak

Form hatalarını, doğrulama başarısızlıklarını ve şüpheli istekleri ölçmek; saldırı denemelerini erken yakalamanıza yardımcı olur. Loglarda PII bilgilerini maskelemek, hem güvenlik hem uyumluluk açısından iyi bir pratiktir.


Ekibin hızlanması için tekrar kullanılabilir şablon kurmak

Tek bir formu güvenli hale getirmek iyi bir başlangıçtır; ancak asıl kazanç, bunu tüm projeye yayabilmektir. Doğrulama fonksiyonları, CSRF yardımcıları, çıktı kaçışlama ve veritabanı erişim katmanını küçük, test edilebilir parçalara ayırmak; bakım maliyetini düşürür.

Eğitimle ortak dil kurmak ve standartları yerleştirmek

Takım içinde aynı yaklaşımı benimsemek, hataları azaltır ve teslim hızını artırır. Uygulamalı örneklerle ilerleyen bir program, herkesin aynı kontrol listesini kullanmasını kolaylaştırır. Daha kapsamlı pratik için PHP eğitimi sayfasındaki içerik akışına göz atabilirsiniz.

 Vimaj