Dizgeleri birbirine yapıştırarak kurulan bir sorgu, sizin buyruklarınızı bir başkasının verisiyle karıştırır. Veritabanı hangisinin hangisi olduğunu ayırt edemez - böylece özenle seçilmiş bir değer, değer olmaktan çıkıp sorunun bir parçası olur.

// wrong, and it is wrong even if you escape
$sql = "SELECT * FROM users WHERE email = '" . $email . "'";

Çare kaçış değildir

Kaçış, tehlikeli veriyi güvenli kılmaya çalışır. Hazır deyimler ise veriyi AYRI OLARAK ULAŞTIRIR; böylece veri hiçbir zaman buyruk olarak okunamaz. Veritabanına önce soru, sonra değerler söylenir.

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
Kaçış; bir karakter kümesi yüzünden, iç içe geçmiş bir tırnak yüzünden, başka bir katmandan çoktan geçmiş bir değer yüzünden yanlış gidebilir. Hazır bir deyim bu yollardan yanlış gidemez, çünkü değer SQL metnine hiç dokunmaz.

Bir yer tutucunun olamayacağı şeyler

Bir yer tutucu bir DEĞERİN yerini tutar. Bir tablo adının, bir sütun adının ya da bir sıralama yönünün yerini tutamaz - onlar sorunun parçasıdır. Bunların girdiden gelmesi gerekiyorsa, kendi yazdığınız bir listeye karşı denetleyin.

$allowed = ['created_at', 'total', 'status'];
$sort = in_array($in, $allowed, true) ? $in : 'created_at';
$sql = "SELECT * FROM orders ORDER BY $sort DESC";

Sizde olanları bulun

grep -rn "SELECT.*\$_\(GET\|POST\|REQUEST\)" --include="*.php" . | head

Dizgenin içinde bir süperglobal barındıran her sorgu, aranan örüntüdür. Genelde bir avuç tanedirler ve genelde eskidirler.

Ve ikinci savunma hattı

Uygulama kullanıcısına yalnızca ihtiyacı olanı verin - tek bir veritabanı üzerinde dört fiil. Tablo silemeyen bir hesap üzerinden başarılı olan bir enjeksiyon, silebilen bir hesap üzerinden olandan çok daha az zarar verir.

Bir ORM, siz onun ham sorgu yardımcısını kullanana kadar parametreleştirmeyi sizin yerinize yapar. Modern kodda enjeksiyonların yaşadığı yer, işte o yardımcıdır.