Reklam Alanı
Siber Güvenlik
Siber Güvenlik

SQL Injection: Kök Neden Analizi ve Parametreli Sorgularla Kalıcı Çözüm

9 Eylül 2026 · 4 dk okuma · 36 okunma

SQL Injection, yirmi yılı aşkın süredir güvenlik zafiyet listelerinin başında yer almasına rağmen hâlâ üretim ortamlarında karşımıza çıkmaya devam eder. Bunun nedeni zafiyetin karmaşık olması değil, kök nedeninin çoğu zaman yanlış anlaşılmasıdır. Sorun "kullanıcı girdisine güvenmemek" gibi genel bir ilkeye indirgendiğinde çözüm de genellikle yüzeysel kalır: girdiyi filtrelemeye çalışan kara liste fonksiyonları, tek tırnak karakterini kaçışlayan (escape) yamalar. Oysa kök neden çok daha yapısaldır: SQL sorgusu içinde kod (komutlar) ile veri (kullanıcı girdisi) aynı metin kanalından, aynı string olarak veritabanı motoruna gönderilir. Motor bu ikisini ayırt edemediği için, girdi içine yerleştirilmiş bir tek tırnak, motor tarafından veri değil sözdizimi olarak yorumlanabilir.

Güvensiz ve güvenli kodun karşılaştırılması

Aşağıdaki örnekte klasik string birleştirme yaklaşımı ile PDO'nun parametreli sorgu mekanizması karşılaştırılmıştır:

// GÜVENSİZ: kullanıcı girdisi doğrudan sorgu metnine ekleniyor
$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $id;
$result = $pdo->query($sql);

// GÜVENLİ: sorgu planı ve veri ayrı kanallardan gönderiliyor
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $_GET['id']]);
$result = $stmt->fetchAll();

Güvensiz örnekte id parametresine 0 OR 1=1 gibi bir değer verildiğinde, motor bunu tamamen geçerli bir SQL koşulu olarak çalıştırır ve tüm kayıtları döndürür; çünkü motorun gözünde ortada tek bir sorgu metni vardır, "burası kod burası veri" ayrımı yoktur. Güvenli örnekte ise veritabanı sürücüsü önce sorgu planını (WHERE id = ?) derler ve bu plana sonradan hangi değer bağlanırsa bağlansın, bağlanan değer daima bir literal veri olarak ele alınır; asla sözdizimi parçası olarak yorumlanmaz. Bu, filtreleme değil, mimari düzeyde bir ayrıştırmadır ve bu yüzden "kalıcı çözüm" olarak nitelendirilir.

Escaping neden yetersiz kalır

Bazı ekipler mysql_real_escape_string benzeri fonksiyonlarla tek tırnak karakterini kaçışlayarak sorunu çözdüğünü düşünür. Ancak bu yaklaşım bağlama duyarlıdır ve kolayca atlanabilir: sayısal bir sütun tırnaksız kullanıldığında escaping hiçbir işe yaramaz, LIKE ifadelerinde joker karakterlerin (%, _) ayrıca ele alınması gerekir, çok baytlı karakter kodlaması hataları geçmişte escaping mekanizmalarını atlatan gerçek saldırı vektörleri oluşturmuştur. Ayrıca sütun adı veya sıralama yönü gibi SQL sözdiziminin kendisine ait öğeler parametre olarak bağlanamaz; bu durumlarda girdinin izin verilen değerlerle karşılaştırıldığı bir beyaz liste (whitelist) yaklaşımı zorunludur.

Savunma derinliği: tek katmana güvenmemek

Parametreli sorgular birincil ve en kritik önlem olsa da, olgun bir güvenlik mimarisi bunu tek başına yeterli görmez. Veritabanı hesabına yalnızca gerektiği kadar yetki verilmesi (en az ayrıcalık ilkesi), bir uygulama katmanı zafiyeti istismar edilse bile saldırganın erişebileceği veri kapsamını sınırlar. Web uygulama güvenlik duvarı (WAF), bilinen saldırı imzalarını yakalayarak ek bir katman sağlar ancak yeni veya gizlenmiş payload'ları atlatabildiği için asla ana savunma olarak kullanılmamalıdır. Zamanlama tabanlı (time-based blind) SQL Injection gibi, uygulamanın herhangi bir hata mesajı döndürmediği ama sorgu yanıt süresindeki farklardan bilgi sızdırılabilen varyantların varlığı da, hata mesajlarını gizlemenin tek başına koruma sağlamadığını gösterir. Konuyla bağlantılı diğer güvenli kodlama pratikleri için siber güvenlik kategorimizi takip edebilirsiniz.

İlgili Yazılar