Arif

WFN Üye
Konular
706
Mesajlar
706
Çözüm
0
Ticaret Puanı
0
Üyelik
24 Gün
Konum
Bilecik
Web Sitesi
Var
Alanı
SEO Uzmanı
1/1
Konu sahibi
Form verisini güvenli işlemek için önce gelen alanları beklenen türe ve biçime göre doğrulayın, geçersizse kaydetme işlemine geçmeden hatayı gösterin; veritabanına yazarken hazırlanmış sorgular, parolalarda password_hash(), HTML çıktısında ise htmlspecialchars() kullanın. Ayrıca form gönderiminde CSRF koruması uygulayın. Böylece doğrulama hataları kullanıcıya geri bildirilebilir, kötü amaçlı girdiler ise veritabanı sorgusunu veya sayfa çıktısını doğrudan etkileyemez.

Doğrulama ile temizleme arasındaki fark​


Doğrulama, verinin kurala uyup uymadığını kontrol eder. Örneğin yaş alanının tam sayı olması, e-posta adresinin geçerli biçimde bulunması veya kullanıcı adının yalnızca izin verilen karakterleri içermesi doğrulama konusudur. Temizleme ise veriyi belirli bir kullanım için dönüştürür; ancak temizleme, geçersiz girdiyi otomatik olarak güvenli veya doğru hâle getirmez.

Bu nedenle kullanıcıdan gelen değeri önce alın, beklenen biçimde doğrulayın ve yalnızca geçerliyse işleme devam edin. Hata mesajlarında kullanıcının gönderdiği değeri doğrudan HTML içine yerleştirmeyin; yeniden göstermeniz gerekiyorsa HTML bağlamına göre kaçışlayın.

Form verisini güvenli sırayla işleme​


Aşağıdaki örnek varsayımsal bir kayıt formunu işler. form.php dosyasına gönderilen ad, email, yas ve sifre alanlarını kontrol eder. Veritabanı bağlantısı için PDO kullanıldığı ve $pdo değişkeninin daha önce oluşturulduğu varsayılmıştır.

PHP:
<?php
declare(strict_types=1);

$hatalar = [];
$eskiVeriler = [
    'ad' => '',
    'email' => '',
    'yas' => '',
];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $ad = trim((string) ($_POST['ad'] ?? ''));
    $email = trim((string) ($_POST['email'] ?? ''));
    $yas = trim((string) ($_POST['yas'] ?? ''));
    $sifre = (string) ($_POST['sifre'] ?? '');

    $eskiVeriler = [
        'ad' => $ad,
        'email' => $email,
        'yas' => $yas,
    ];

    if ($ad === '' || mb_strlen($ad) < 2 || mb_strlen($ad) > 100) {
        $hatalar['ad'] = 'Ad 2 ile 100 karakter arasında olmalıdır.';
    }

    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $hatalar['email'] = 'Geçerli bir e-posta adresi girin.';
    }

    if (filter_var($yas, FILTER_VALIDATE_INT) === false) {
        $hatalar['yas'] = 'Yaş tam sayı olmalıdır.';
    } else {
        $yasSayisi = (int) $yas;
        if ($yasSayisi < 18 || $yasSayisi > 120) {
            $hatalar['yas'] = 'Yaş 18 ile 120 arasında olmalıdır.';
        }
    }

    if (mb_strlen($sifre) < 12) {
        $hatalar['sifre'] = 'Parola en az 12 karakter olmalıdır.';
    }

    if ($hatalar === []) {
        $sifreHash = password_hash($sifre, PASSWORD_DEFAULT);

        $sorgu = $pdo->prepare(
            'INSERT INTO kullanicilar (ad, email, yas, sifre_hash)
             VALUES (:ad, :email, :yas, :sifre_hash)'
        );

        $sorgu->execute([
            'ad' => $ad,
            'email' => $email,
            'yas' => $yasSayisi,
            'sifre_hash' => $sifreHash,
        ]);

        header('Location: kayit-basarili.php');
        exit;
    }
}

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

Kodda $_POST değerleri doğrudan kullanılmıyor; alan bulunmadığında boş değer atanıyor, metin alanlarında baştaki ve sondaki boşluklar kaldırılıyor. Ancak trim() tek başına doğrulama değildir. Örneğin e-posta için ayrıca FILTER_VALIDATE_EMAIL, yaş için tam sayı ve aralık kontrolü uygulanıyor.

filter_var() ile yapılan kontrolün sonucu yalnızca biçimin uygun olduğunu gösterir. E-posta adresinin gerçekten kullanıcıya ait olduğunu veya kişinin belirtilen yaşı taşıdığını kanıtlamaz. Böyle bir kanıt gerekiyorsa ayrıca e-posta doğrulama bağlantısı, kimlik doğrulama veya iş kurallarına uygun başka bir süreç gerekir.

Hatalı sonuçta ne yapılır?​


$hatalar dizisi boş değilse form veritabanına yazılmaz. Kullanıcıya hangi alanın neden kabul edilmediği gösterilir; geçerli alanların değerleri yeniden sunulabilir. Parola gibi hassas değerler yeniden forma yazılmamalı ve hata çıktısında gösterilmemelidir.

Formun HTML tarafında hata mesajlarını ve eski değerleri güvenli biçimde üretin:

HTML:
<input type="text" name="ad" value="<?= e($eskiVeriler['ad']) ?>">
<?php if (isset($hatalar['ad'])): ?>
    <p><?= e($hatalar['ad']) ?></p>
<?php endif; ?>

<input type="email" name="email" value="<?= e($eskiVeriler['email']) ?>">
<?php if (isset($hatalar['email'])): ?>
    <p><?= e($hatalar['email']) ?></p>
<?php endif; ?>

htmlspecialchars() burada HTML özniteliği ve metin içeriği için çıktıyı kaçışlar. Bu işlem veriyi veritabanına kaydetmeden önce yapılacak genel bir “temizleme” yöntemi değildir; HTML çıktısı oluşturulurken uygulanır. Aynı veri JavaScript, URL, SQL veya CSS içinde kullanılacaksa o bağlama uygun yöntem gerekir.

Her katmanda farklı güvenlik önlemi kullanın​


Form güvenliği tek bir fonksiyonla sağlanmaz. Kullanım amacına göre doğru önlem seçilmelidir.
İşlemDoğru yaklaşımNeyi sağlar?
Alan doğrulamaTür, uzunluk, biçim ve aralık kontrolüBeklenmeyen veya eksik veriyi reddeder
SQL sorgusuPDO hazırlanmış sorguları ve parametreleri kullanmaGirdinin SQL komutu olarak yorumlanmasını önler
HTML çıktısıBağlama uygun çıktı kaçışlama, HTML için htmlspecialchars()XSS riskini azaltır
Parola saklamapassword_hash() kullanmaParolayı düz metin olarak saklamaz
Form gönderimiCSRF belirteci doğrulamaBaşka bir siteden kullanıcının oturumu üzerinden istenmeyen işlem yapılmasını önlemeye yardımcı olur
Tabloya göre örneğin htmlspecialchars() SQL enjeksiyonunu çözmez; hazırlanmış sorgular da HTML çıktısındaki XSS riskini çözmez. Her veri, kullanıldığı bağlama göre ayrıca korunmalıdır.

CSRF korumasını ekleme​


Oturum açmış kullanıcının hesabında değişiklik yapan veya veritabanına kayıt ekleyen formlarda sunucu tarafında CSRF belirteci kontrol edin. Formu üretirken oturumda rastgele bir belirteç oluşturup gizli alana koyun; POST isteği geldiğinde formdan gelen değer ile oturumdaki değeri zamanlama saldırılarına dayanıklı karşılaştırmayla kontrol edin.

PHP:
<?php
session_start();

if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $gelenToken = (string) ($_POST['csrf_token'] ?? '');

    if (!hash_equals($_SESSION['csrf_token'], $gelenToken)) {
        http_response_code(403);
        exit('Geçersiz form isteği.');
    }
}

Form içinde tokenı şu şekilde gönderin:

HTML:
<input type="hidden" name="csrf_token" value="<?= e($_SESSION['csrf_token']) ?>">

Tokenın geçersiz olması, kullanıcının form alanlarını yanlış doldurduğu anlamına gelmez; isteğin beklenen form oturumundan gelmediğini gösterir. Bu durumda kayıt işlemini durdurun. Kullanıcıya tekrar form açtırmak gerekiyorsa yeni bir sayfa isteğiyle yeni veya geçerli oturum tokenını üretin.

Kayıt başarılı olduktan sonra sonucu kontrol etme​


Doğrulama hatası yoksa hazırlanmış sorguyu çalıştırın ve işlem başarısız olursa uygulamanın hata ayrıntılarını kullanıcıya göstermeyin. Geliştirme ortamında günlük kaydı tutulabilir; üretim ortamında SQL sorgusu, bağlantı bilgileri, parola veya tam hata yığını tarayıcıya gönderilmemelidir.

Kayıt başarılı olduğunda POST isteği sonrasında yönlendirme yapmak, sayfa yenilendiğinde formun yeniden gönderilmesini önler. Yönlendirilen başarı sayfası yalnızca “kayıt tamamlandı” mesajı göstermeli; kullanıcının gönderdiği parola veya hassas form verilerini URL parametresine taşımamalıdır.

E-posta alanının veritabanında benzersiz olması gerekiyorsa bunu yalnız PHP kontrolüne bırakmayın. Uygulama tarafındaki ön kontrol kullanıcıya hızlı hata gösterebilir, ancak aynı anda gelen iki isteği kesin olarak engellemek için veritabanında UNIQUE kısıtı da bulunmalıdır. Kısıt ihlalinde sorgu hatasını yakalayıp e-posta adresinin zaten kullanıldığını belirten genel bir hata döndürün.

Sık yapılan hatalar​

  • $_POST['alan'] değerini kontrol etmeden kullanmak: Alan hiç gönderilmezse uyarı veya hatalı işleme oluşabilir.
  • Yalnız istemci tarafı JavaScript doğrulamasına güvenmek: İstemci kontrolleri devre dışı bırakılabildiği için sunucu tarafı doğrulama zorunludur.
  • SQL sorgusunu string birleştirmeyle oluşturmak: Kullanıcı verisi SQL komutuna karışabilir; hazırlanmış sorgu kullanın.
  • Parolayı düz metin veya geri döndürülebilir şifreleme ile saklamak: Parola için password_hash() ve giriş kontrolünde password_verify() kullanın.
  • Hata mesajını doğrudan HTML’e yazmak: Kullanıcı girdisini çıktı bağlamına uygun şekilde kaçışlayın.
  • Geçersiz girdiyi sessizce düzeltip kaydetmek: Kullanıcıya hangi kuralın uygulanamadığını bildirin; aksi hâlde kaydedilen veri beklenenden farklı olabilir.
Bir formun doğru çalıştığını anlamak için yalnızca başarılı kayıt senaryosunu değil; eksik alanı, geçersiz e-postayı, sınır dışı yaşı, uzun metni, bozuk CSRF tokenını ve veritabanındaki yinelenen e-postayı da ayrı ayrı kontrol edin. Her hatada beklenen sonuç kayıt işleminin yapılmaması, anlaşılır bir hata gösterilmesi ve hassas teknik ayrıntının kullanıcıya açılmamasıdır.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Foruma git ?

Bu konuyu görüntüleyen kullanıcılar

Bu konuyu şu anda görüntüleyen üye bulunmuyor.
Robotlar:
  • Anthropic