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.