استعلامات PDO المحضرة: حماية 100% من حقن SQL؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: السؤال الذي يقلق كل مطور PHP

\n\n

إذا سبق لك كتابة استعلامات SQL في PHP، فبالتأكيد سمعت هذه المقولة: "استخدم PDO والاستعلامات المحضرة وستكون في أمان تام". ولكن هل هذا صحيح حقًا؟ على Stack Overflow، سؤال "Are PDO prepared statements sufficient to prevent SQL injection?" حصد آلاف المشاهدات وعشرات النقاشات الساخنة. وهذا ليس بدون سبب.

\n\n

في هذا المقال، لن نقدم إجابة مختصرة بـ"نعم" أو "لا". بل سنتعمق في آلية عمل PDO، ونفهم كيف تعمل الاستعلامات المحضرة بالضبط، ونكتشف الحالات التي قد يخذلك فيها PDO. هل أنت مستعد؟ فلنبدأ.

\n\n

ما هو حقن SQL ولماذا هو خطير؟

\n\n

قبل الحديث عن الحماية، دعنا نتعرف على العدو. حقن SQL هو هجوم يقوم فيه المخترق بحقن كود SQL ضار عبر بيانات الإدخال. المثال الكلاسيكي:

\n\n
// كود سيء: لا تفعل هذا أبدًا\n$username = $_POST['username'];\n$query = "SELECT * FROM users WHERE username = '$username'";\n$result = mysqli_query($conn, $query);\n
\n\n

إذا أدخل المخترق admin' OR '1'='1، يتحول الاستعلام إلى:

\n\n
SELECT * FROM users WHERE username = 'admin' OR '1'='1'\n
\n\n

وهكذا يتم الوصول إلى البيانات بدون كلمة مرور. وإذا أدخل '; DROP TABLE users; --؟ وداعًا لجدول المستخدمين.

\n\n

PDO والاستعلامات المحضرة: كيف تعمل؟

\n\n

PDO (PHP Data Objects) يوفر آلية prepared statements (الاستعلامات المحضرة). الفكرة بسيطة: تفصل هيكل الاستعلام عن البيانات. بدلاً من إدخال المتغيرات مباشرة في النص، تستخدم عناصر نائبة (placeholders):

\n\n
// كود آمن باستخدام PDO\n$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");\n$stmt->execute([':username' => $_POST['username']]);\n
\n\n

ولكن ماذا يحدث تحت الغطاء؟ هذه هي النقطة الأساسية التي يغفل عنها الكثيرون.

\n\n

وضع المحاكاة مقابل الاستعلامات المحضرة الأصلية

\n\n

يمكن لـ PDO العمل في وضعين:

\n\n
    \n
  • وضع المحاكاة (الافتراضي في الإصدارات القديمة من PHP) — يقوم PDO بتنظيف البيانات وإدراجها في الاستعلام من جانب PHP. هذا لا يزال آمنًا، لكنه قد يكون عرضة للاختراق نظريًا إذا تعطلت عملية التنظيف (مثلًا عند التعامل مع ترميزات غير قياسية).
  • \n
  • الوضع الأصلي — يرسل PDO رسالتين إلى خادم قاعدة البيانات: الأولى تحتوي على قالب الاستعلام، والثانية تحتوي على البيانات بشكل منفصل. يتعامل الخادم مع البيانات كقيم وليس ككود. هذا آمن تمامًا.
  • \n
\n\n

لتفعيل الوضع الأصلي، قم بتعطيل المحاكاة:

\n\n
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);\n
\n\n

الآن يتم إرسال الاستعلام إلى الخادم على مرحلتين. حتى لو أدخل المخترق ' OR '1'='1، فإن خادم MySQL أو PostgreSQL سيتعامل معها كقيمة نصية وليس كجزء من كود SQL. سحر!

\n\n

ولكن هل كل شيء مثالي؟ عيوب PDO الخفية

\n\n

لنعد إلى سؤال Stack Overflow. الإجابة "نعم، استعلامات PDO المحضرة كافية" — ولكن مع تحفظات. إليك الحالات التي قد تفشل فيها الحماية.

\n\n

1. المعرفات الديناميكية (أسماء الجداول والأعمدة)

\n\n

الاستعلامات المحضرة تعمل فقط مع القيم (البيانات). إذا كنت تدرج اسم جدول أو عمود، فلن تساعدك العناصر النائبة:

\n\n
// خطير! لا يمكن تمرير اسم الجدول عبر عنصر نائب\n$stmt = $pdo->prepare("SELECT * FROM :table WHERE id = :id");\n$stmt->execute([':table' => $_GET['table'], ':id' => 1]); // خطأ!\n
\n\n

سيقوم PDO بإدراج اسم الجدول كنص، وسيفشل الاستعلام. وإذا كنت تستخدم وضع المحاكاة، يمكن للمخترق إدخال users; DROP TABLE users; --. الحل: قائمة بيضاء من القيم المسموح بها.

\n\n

2. استعلامات LIKE ورموز الاستبدال

\n\n

إذا كنت تستخدم

المدونات

توصيات الكتب