SQL injection'ı anlamak için tek bir satır yeter. Şu masum görünen giriş sorgusuna bakın:
$sql = "SELECT * FROM users WHERE email = '" . $_POST["email"] . "'";Saldırgan e-posta alanına şunu yazarsa:
' OR 1=1 --oluşan sorgu WHERE email = '' OR 1=1 hâline gelir; koşul her satır için doğrudur ve saldırgan ilk kullanıcı (çoğu zaman yönetici!) olarak içeri girer.
Bu, teorik bir risk değil: OWASP Top 10 listesinde injection, yıllardır ilk üç sırada. Otomatik botlar interneti sürekli bu açık için tarar.
Çözüm: Prepared Statements
Sorgu şablonu ile veriyi ayrı kanallardan gönderirseniz, veri asla SQL olarak yorumlanamaz:
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$_POST["email"]]);
$user = $stmt->fetch();Saldırgan ne yazarsa yazsın, girdiği metin yalnızca aranacak değer olur - sorgunun yapısını değiştiremez.
PDO açarken PDO::ATTR_EMULATE_PREPARES => false ayarını verin; böylece sorgular gerçek anlamda sunucu tarafında hazırlanır.
Sık sorulan: "Girdileri temizlesem yetmez mi?"
Hayır. Kara liste tabanlı temizlik her zaman atlatılabilir (kodlama hileleri, çok baytlı karakterler...). Prepared statement yapısal bir çözümdür: açık sınıfını tümden ortadan kaldırır. Temizlik/doğrulama yine yapın - ama iş kuralları için, güvenlik için değil.
Bu sitenin tüm veritabanı katmanı prepared statement kullanır; merak edenler için kaynak yapısını blogda paylaşacağım.
