Gereksinimler ve Ön Hazırlık
Bu rehberdeki uygulamaları gerçekleştirmek için güncel bir veritabanı yönetim sistemine (PostgreSQL 17+ veya MySQL 9.0+ önerilir) ve bir uygulama sunucusuna ihtiyacınız vardır. SQL sorgularını çalıştırmak için terminal veya bir veritabanı istemcisi (DBeaver, pgAdmin vb.) kullanabilirsiniz.
- Veritabanı: PostgreSQL veya MySQL güncel kararlı sürüm.
- Programlama Dili: Örneklerde genel kabul görmüş SQL standartları ve uygulama katmanı için sözde kod (pseudo-code) mantığı kullanılacaktır.
- Güvenlik Araçları: Veri girişi sırasında kullanılacak parametreli sorgu (prepared statements) kütüphaneleri.
Veritabanı Seviyesinde Kısıtlamalar (Constraints) ile Validasyon
Veritabanı seviyesinde yapılan validasyon, uygulamanızın hangi dili kullandığından bağımsız olarak verinin doğruluğunu garanti eder. Veritabanı şeması oluştururken kullanılan CHECK, NOT NULL ve UNIQUE kısıtlamaları, hatalı verinin tabloya girmesini fiziksel olarak engeller.
CREATE TABLE kullanicilar (
id SERIAL PRIMARY KEY,
eposta VARCHAR(255) UNIQUE NOT NULL,
yas INT CHECK (yas >= 18),
kayit_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Yukarıdaki örnekte CHECK kısıtlaması, 18 yaşından küçük kullanıcıların sisteme kaydedilmesini veritabanı düzeyinde reddeder. Bu, uygulama katmanında bir hata olsa dahi veritabanınızın bütünlüğünü korur.
Parametreli Sorgular ile SQL Injection Koruması
Veri validasyonunun en önemli parçası, kullanıcıdan gelen veriyi doğrudan sorgu içine gömmemektir. SQL Injection, saldırganların kötü niyetli SQL komutlarını sorgularınıza enjekte etmesidir. Bunu engellemek için her zaman "Prepared Statements" (Hazırlanmış İfadeler) kullanmalısınız.
-- Güvensiz Yöntem (ASLA YAPMAYIN)
-- SELECT * FROM kullanicilar WHERE eposta = ' + kullanici_girdisi + ';
-- Güvenli Yöntem (Parametreli Sorgu)
PREPARE sorgu_hazirla (text) AS
SELECT * FROM kullanicilar WHERE eposta = $1;
EXECUTE sorgu_hazirla('kullanici@ornek.com');
Parametreli sorgular, veritabanına veriyi komuttan ayrı bir kanaldan gönderir. Böylece veritabanı motoru, gelen veriyi bir komut olarak değil, sadece bir değer (string/int) olarak işler.
Uygulama Katmanında Veri Doğrulama Adımları
Veritabanına gitmeden önce, uygulama katmanında (Backend) veriyi temizlemek (sanitization) ve doğrulamak (validation) gerekir. Bu, gereksiz veritabanı sorgularını azaltır ve kullanıcıya daha hızlı geri bildirim sağlar.
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Veritabanı Constraints | %100 Güvenli ve tutarlı | Hata mesajları kullanıcıya zor iletilir |
| Uygulama Validasyonu | Hızlı ve kullanıcı dostu | Güvenlik için tek başına yeterli değil |
Uygulama katmanında yapılacak validasyon, verinin formatını (e-posta formatı, telefon numarası uzunluğu vb.) kontrol etmelidir. Örneğin, bir e-posta adresinin geçerli olup olmadığını regex ile kontrol etmek ilk adımdır.
Veri Temizleme (Sanitization) Teknikleri
Veri temizleme, kullanıcıdan gelen verideki zararlı karakterlerin (HTML tagleri, script blokları) ayıklanması işlemidir. Özellikle web uygulamalarında XSS (Cross-Site Scripting) saldırılarını önlemek için bu adım zorunludur.
function temizle(veri) {
// HTML karakterlerini kaçış dizilerine çevir
return veri.replace(/&/g, "&").replace(//g, ">");
}
let kullanici_adi = temizle("alert('xss')");
// Sonuç: alert('xss')
Bu işlem, verinin veritabanına kaydedilmeden önce zararsız bir metin haline getirilmesini sağlar. Ancak unutmayın, veritabanından veri çekerken de benzer bir temizlik işlemi (Output Encoding) yapmanız gerekir.
İş Mantığı Validasyonu (Business Logic)
Bazen verinin formatı doğru olsa bile iş mantığına göre hatalı olabilir. Örneğin, bir bankacılık uygulamasında, kullanıcının bakiyesinden daha fazla para çekmeye çalışması teknik olarak geçerli bir sayısal veridir, ancak iş mantığına göre geçersizdir.
-- İş mantığı kontrolü içeren prosedür
CREATE OR REPLACE PROCEDURE bakiye_guncelle(k_id INT, miktar DECIMAL)
LANGUAGE plpgsql AS $$
BEGIN
IF (SELECT bakiye FROM hesaplar WHERE id = k_id) < miktar THEN
RAISE EXCEPTION 'Yetersiz bakiye!';
END IF;
UPDATE hesaplar SET bakiye = bakiye - miktar WHERE id = k_id;
END;
$$;
Bu tür kontrolleri veritabanı içerisinde prosedürler veya tetikleyiciler (triggers) ile yönetmek, uygulamanızın tutarlılığını artırır.
Kritik Güvenlik Uyarısı: Veritabanı işlemlerinde asla kullanıcı girdilerini doğrudan birleştirerek sorgu oluşturmayın. Her zaman ORM (Object-Relational Mapping) araçlarının sunduğu güvenli sorgu yöntemlerini veya parametreli sorguları tercih edin. Üretim ortamında hata mesajlarını kullanıcılara doğrudan göstermeyin, sadece loglayın.
Sıkça Sorulan Sorular
Veri validasyonu için veritabanı kısıtlamaları yeterli midir?
Hayır, veritabanı kısıtlamaları son savunma hattıdır. Uygulama katmanında da validasyon yaparak kullanıcıya daha iyi bir deneyim sunmalı ve gereksiz veritabanı trafiğini önlemelisiniz.
SQL Injection'dan korunmak için en iyi yöntem nedir?
En iyi yöntem, her zaman parametreli sorgular (prepared statements) kullanmaktır. Dinamik SQL oluşturmaktan kaçınmalısınız.
Regex ile validasyon yapmak performans kaybı yaratır mı?
Çok karmaşık regex ifadeleri yüksek trafikli sistemlerde maliyetli olabilir. Ancak standart e-posta veya telefon formatı kontrolleri için performans etkisi ihmal edilebilir düzeydedir.
Veritabanı tetikleyicileri (triggers) neden kullanılmalı?
Tetikleyiciler, veritabanında gerçekleşen bir işlem (INSERT, UPDATE, DELETE) öncesinde veya sonrasında otomatik olarak çalışır. Veri bütünlüğünü zorunlu kılmak için mükemmel bir araçtır.
Veri temizleme (sanitization) veritabanına kaydetmeden önce mi yapılmalı?
Evet, veritabanına kaydedilmeden önce temizlenmelidir. Ancak veriyi ekrana basarken de "Output Encoding" yaparak XSS saldırılarına karşı ikinci bir koruma katmanı oluşturmalısınız.
Veri Validasyon Süreçlerinde Hata Ayıklama ve Loglama Stratejileri
Uygulama geliştirme sürecinde, veri validasyon kurallarınızın beklendiği gibi çalışıp çalışmadığını anlamak için sağlam bir hata ayıklama (debugging) ve loglama mekanizmasına ihtiyacınız vardır. Validasyon hataları genellikle sessizce başarısız olur; bu da veritabanına hatalı veri girmesine veya kullanıcının hiçbir geri bildirim almadan işlem yapamamasına neden olur.
Hata ayıklama sürecini iyileştirmek için veritabanı seviyesinde yakalanan kısıtlama ihlallerini uygulama katmanına anlamlı hata mesajları olarak dönüştürmelisiniz. Örneğin, bir CHECK kısıtlaması ihlal edildiğinde veritabanından dönen ham hata kodunu doğrudan kullanıcıya göstermek yerine, bunu bir "Exception Handler" ile yakalayıp kullanıcı dostu bir mesaja çevirmelisiniz.
try {
$db->execute("INSERT INTO users (age) VALUES (?)", [$inputAge]);
} catch (PDOException $e) {
if ($e->getCode() == '23514') { // PostgreSQL check_violation kodu
error_log("Validasyon Hatası: Yaş kısıtlaması ihlal edildi. Değer: " . $inputAge);
throw new Exception("Lütfen geçerli bir yaş değeri giriniz (18-99).");
}
}
Validasyon Performansını Optimize Etme Yöntemleri
Veri validasyonu, özellikle yüksek trafikli uygulamalarda darboğaz oluşturabilir. Özellikle karmaşık Regex (Düzenli İfadeler) kullanımı veya veritabanına her kayıt öncesi yapılan "lookup" sorguları, sistemin yanıt süresini doğrudan etkiler. Performans kaybını minimize etmek için şu stratejileri izleyebilirsiniz:
- İstemci Tarafı Validasyon: Sunucuya yük binmeden önce temel kontrolleri (boşluk kontrolü, uzunluk, format) JavaScript ile yapın.
- Erken Dönüş (Early Return) Prensibi: En ucuz maliyetli validasyonları (tip kontrolü, uzunluk) en başta yapın. Veritabanı sorgusu gerektiren ağır kontrolleri en sona bırakın.
- Önbellekleme (Caching): Sıkça kontrol edilen statik verileri (ülke kodları, posta kodu formatları gibi) bellek üzerinde (Redis/Memcached) tutarak veritabanı sorgularını azaltın.
Aşağıdaki örnekte, gereksiz veritabanı sorgularını engelleyen bir validasyon akışı görülmektedir:
function validateUserRegistration($data) {
// 1. Basit kontrol (Hızlı)
if (strlen($data['username']) < 3) return false;
// 2. Format kontrolü (Regex)
if (!preg_match('/^[a-zA-Z0-9]+$/', $data['username'])) return false;
// 3. Veritabanı kontrolü (Ağır - Sadece yukarıdakiler geçilirse çalışır)
return !$this->db->exists("SELECT 1 FROM users WHERE username = ?", [$data['username']]);
}
Validasyon Testleri: Birim Testler ile Güvence
Validasyon mantığınızın her zaman çalıştığından emin olmak için "Unit Testing" (Birim Testleri) yazmak zorunludur. Özellikle uç durumları (edge cases) test etmek, sistemin beklenmedik veri girişlerine karşı direncini artırır. Test senaryolarınızda şu durumları mutlaka kapsayın:
| Senaryo | Beklenen Sonuç |
|---|---|
| Negatif yaş girişi | Hata döndürülmeli |
| SQL Injection karakterleri içeren string | Sanitize edilmeli veya reddedilmeli |
| Maksimum karakter sınırını aşan girdi | Hata döndürülmeli |
Test yazarken, veritabanı ile etkileşime girmeyen "Mock" nesneler kullanarak validasyon fonksiyonlarınızın mantığını izole bir şekilde test etmeniz, testlerinizin hızlı çalışmasını sağlar.
Sonuç
Sql & veritabanı ile uygulamalar için veri validasyon kontrolü yapmak, uygulamanızın ömrünü uzatan ve güvenliğini sağlayan bir disiplindir. Bu makalede öğrendiğiniz parametreli sorgular, veritabanı kısıtlamaları ve veri temizleme tekniklerini projenize entegre ederek, 2026 yılı standartlarında güvenli bir mimari oluşturabilirsiniz. Bir sonraki adım olarak, veritabanı loglama ve anomali tespiti üzerine çalışarak sisteminizin güvenliğini bir üst seviyeye taşımanızı öneririm.


Yorumlar (0)
Yorum Yaz