أمان PHP: كيفية حماية موقعك من هجمات SQL injection و XSS

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

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

ابدأ الدورة

موقع PHP الخاص بك تحت المجهر: لماذا يحب المخترقون الأمان الضعيف

\n\n

تخيل: لقد أمضيت أسابيع في تطوير مدونة رائعة أو متجر إلكتروني باستخدام PHP. الموقع يعمل، والزوار سعداء. ولكن في يوم "جميل"، تدخل إلى لوحة التحكم، فتجدها فارغة. تم حذف قاعدة البيانات. أو ما هو أسوأ، تظهر إعلانات كازينو على الصفحة الرئيسية، ويتم إعادة توجيه جميع المستخدمين إلى موقع تصيد.

\n\n

قصة مألوفة؟ لسوء الحظ، بالنسبة للعديد من مطوري PHP المبتدئين (وليس فقط)، هذا هو الواقع. الأمر المحبط هو أن 90% من هذه الهجمات تحدث بسبب ثغرات تبدو بسيطة: هجمات SQL injection و البرمجة النصية عبر المواقع (XSS). لا يخترق القراصنة خوارزميات التشفير المعقدة - بل يستغلون ببساطة عدم انتباه المبرمجين.

\n\n

في هذه المقالة، لن نلقي محاضرات مملة. سنفهم كيف تعمل هذه الهجمات "من الداخل"، والأهم من ذلك، سنتعلم كيفية وضع حواجز قوية. ستتعلم كيف تجعل كود PHP الخاص بك صعب المنال على المهاجمين. هيا بنا!

\n\n

هجمات SQL injection: عندما تتحدث قاعدة البيانات بصوت المخترق

\n\n

هجوم SQL injection هو نوع من الهجمات يقوم فيه المهاجم "بإدخال" كود SQL ضار في استعلام قاعدة البيانات. إذا كان تطبيقك لا يقوم بتصفية البيانات المدخلة، يمكن للمخترق أن يجعل قاعدة البيانات تنفذ أي أمر: من سرقة كلمات المرور إلى حذف الجداول بالكامل.

\n\n

كيف يبدو الكود الضعيف؟

\n\n

تخيل نموذج تسجيل دخول بسيط. غالبًا ما يبدو كود المبتدئين هكذا:

\n\n
<?php\n$login = $_POST['login'];\n$password = $_POST['password'];\n\n// خطير! إدخال مباشر في الاستعلام\n$query = "SELECT * FROM users WHERE login = '$login' AND password = '$password'";\n$result = mysqli_query($link, $query);\n?>
\n\n

يبدو منطقيًا. ولكن ماذا سيحدث إذا أدخل المهاجم السلسلة التالية في حقل اسم المستخدم:

\n\n
' OR '1'='1
\n\n

سيتحول الاستعلام إلى:

\n\n
SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '...'
\n\n

الشرط '1'='1' صحيح دائمًا. تهانينا، لقد دخل المخترق للتو إلى النظام بدون كلمة مرور! وإذا أدخل '; DROP TABLE users; --، فسيختفي جدول المستخدمين إلى الأبد.

\n\n

هروب البيانات مقابل الاستعلامات المُعدة مسبقًا: أيهما تختار؟

\n\n

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

\n\n
    \n
  • من السهل نسيان تطبيق الدالة على كل متغير.
  • \n
  • لا تحمي من جميع أنواع الحقن (مثل عند العمل مع LIKE).
  • \n
  • يصبح الكود غير نظيف ويصعب صيانته.
  • \n
\n\n

الطريقة الحديثة والصحيحة هي الاستعلامات المُعدة مسبقًا (prepared statements) عبر PDO أو MySQLi. تفصل هذه الطريقة بين منطق الاستعلام والبيانات. تقوم قاعدة البيانات أولاً "بتجميع" قالب الاستعلام، ثم تقوم بإدخال البيانات فيه. حتى لو قام المخترق بإرسال كود ضار، فسيتم التعامل معه كسلسلة نصية عادية، وليس كجزء من أمر SQL.

\n\n

كتابة كود آمن باستخدام PDO

\n\n

هذا هو الشكل الذي يجب أن يبدو عليه الاستعلام الآمن لقاعدة البيانات باستخدام PDO (كائنات بيانات PHP):

\n\n
<?php\n// الاتصال بقاعدة البيانات\n$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';\n$pdo = new PDO($dsn, 'user', 'password');\n\n// ضبط وضع الأخطاء (مهم للتصحيح، لكن قم بإزالته في الإنتاج)\n$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\n// تحضير الاستعلام (القالب)\n$stmt = $pdo->prepare("SELECT * FROM users WHERE login = :login AND password = :password");\n\n// ربط المعاملات وتنفيذها\n$stmt->execute([\n    ':login' => $_POST['login'],\n    ':password' => $_POST['password']\n]);\n\n$user = $stmt->fetch();\n\nif ($user) {\n    echo "مرحبًا بك!";\n} else {\n    echo "اسم المستخدم أو كلمة المرور غير صحيحة";\n}\n?>
\n\n

حول

المدونات

توصيات الكتب