الاستعلامُ المبنيّ بلصق النصوص يخلط تعليماتك ببيانات شخصٍ آخر. وقاعدةُ البيانات لا تميّز بينهما — فقيمةٌ اختيرت بعناية تكفّ عن كونها قيمةً وتصير جزءًا من السؤال.
// wrong, and it is wrong even if you escape
$sql = "SELECT * FROM users WHERE email = '" . $email . "'";
والعلاج ليس التهريب
التهريبُ يحاول أن يجعل البيانات الخطِرة آمنة. أمّا العباراتُ المُعدَّة فتجعل البيانات تصل على حدة، فلا تُقرأ تعليماتٍ البتّة. تُخبَر قاعدةُ البيانات بالسؤال أوّلًا وبالقيم بعده.
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
ما لا يكونه العنصرُ النائب
العنصرُ النائب يقوم مقام قيمة. ولا يقوم مقام اسم جدولٍ أو اسم عمودٍ أو اتّجاه ترتيب — فتلك جزءٌ من السؤال. وإن لزم أن تأتي من مُدخَل فافحصها مقابل قائمةٍ كتبتها أنت.
$allowed = ['created_at', 'total', 'status'];
$sort = in_array($in, $allowed, true) ? $in : 'created_at';
$sql = "SELECT * FROM orders ORDER BY $sort DESC";
اعثر على ما عندك منها
grep -rn "SELECT.*\$_\(GET\|POST\|REQUEST\)" --include="*.php" . | head
كلُّ استعلامٍ فيه متغيّرٌ فائقُ العموميّة داخل النصّ هو النمط. وهي حفنةٌ في العادة، وقديمةٌ في العادة.
والخطُّ الثاني
امنح مستخدم التطبيق ما يحتاجه لا غير — أربعةَ أفعالٍ على قاعدةٍ واحدة. فحَقنٌ ناجح عبر حسابٍ لا يستطيع حذف جدولٍ يفعل أقلَّ بكثير من حَقنٍ عبر حسابٍ يستطيع.