كيف أؤمّن موقع PHP بعد اختراقه: قائمة التحقق الفعلية لتقوية خادم الويب لديّ

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


من أكبر الأخطاء التي يرتكبها المطورون بعد الاختراق محاولة إصلاح الضرر الظاهر فقط. فهم يحذفون صفحات البريد العشوائي، ويغيّرون كلمة مرور المسؤول، ويحدّثون بعض الإضافات، ويفترضون أن المشكلة قد حُلّت. قد يؤدي ذلك إلى إزالة العَرَض، لكنه لا يزيل بالضرورة الثغرة التي سمحت للمهاجم بالدخول في المقام الأول. إذا ظلت نقطة الدخول الأصلية موجودة، يمكن للمهاجم ببساطة العودة.

أنا أتبع نهجًا مختلفًا. بمجرد اختراق موقع ويب، أفترض أن كل ما يرتبط بذلك التطبيق يحتاج إلى المراجعة. ويشمل ذلك الملفات العامة، وقاعدة البيانات، وإعدادات الخادم، والمهام المجدولة، وحسابات المسؤولين، وأذونات الملفات، ومفاتيح API، وأدلة الرفع، ونظام المصادقة. الهدف ليس تنظيف الموقع فحسب، بل إعادة بناء الثقة في البيئة.

تشرح هذه المقالة نموذج الأمان الذي أستخدمه عند تقوية موقع مخصّص مبني باستخدام PHP وMySQL. تنطبق بعض هذه التقنيات على WordPress وLaravel وSymfony وغيرها من المنصات أيضًا، لكن الأمثلة هنا تركز أساسًا على تطبيقات PHP التقليدية التي تعمل على Apache.

ابدأ بالافتراض الصحيح

أول ما أفترضه بعد اكتشاف الاختراق هو أن المهاجم ربما حصل على صلاحيات وصول أكبر مما يظهر مباشرة. إن العثور على ملف PHP ضار واحد لا يعني وجود ملف PHP ضار واحد فقط. ينشئ المهاجمون عادةً نقاط وصول ثانوية حتى لا يؤدي حذف البرمجية الخبيثة الأصلية إلى منعهم من الدخول.

على سبيل المثال، قد يرفع المهاجم صدفة ويب إلى دليل للصور، أو يحقن PHP في ملف تطبيق شرعي، أو ينشئ حساب مسؤول مخفيًا، أو يعدّل مهمة مجدولة، أو يُدخل JavaScript ضارًا إلى قاعدة البيانات. وقد ينشئون أيضًا ملفات بأسماء تبدو بريئة مثل cache.php أو class.api.php أو system-helper.php لكي تختلط البرمجية الخبيثة مع شفرة التطبيق الشرعية.

ولهذا، فإن ترتيب دليل حسب اسم الملف ليس كافيًا. أريد أن أعرف أي الملفات عُدّلت مؤخرًا، وأي الملفات تحتوي على PHP قابل للتنفيذ، وأي الأدلة تحتوي بشكل غير متوقع على نصوص برمجية، وما إذا كانت هناك ملفات تختلف عن الإصدارات المعروفة بأنها سليمة.

من أوامر Linux المفيدة:

find /var/www/html -type f -mtime -14 -print

يسرد هذا الملفات التي عُدّلت خلال الأربعة عشر يومًا السابقة. ولا يثبت ذلك أن هذه الملفات ضارة، لكنه يمنحك نقطة بداية عند التحقيق في اختراق حدث مؤخرًا.

يمكنك أيضًا البحث عن ملفات PHP داخل الأدلة التي يُفترض عادةً ألا تحتوي إلا على محتوى ثابت:

find /var/www/html/uploads -type f \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" \)

إذا كان من المفترض أن يحتوي دليل التحميل لديك على صور فوتوغرافية وملفات PDF ومستندات المستخدمين، فإن اكتشاف PHP قابل للتنفيذ في ذلك الدليل يستحق تحقيقًا فوريًا.

غيّر كل بيانات الاعتماد التي ربما انكشفت

تغيير كلمة مرور مسؤول الموقع ليس كافيًا. فإذا حصل المهاجم على إمكانية الوصول إلى الخادم أو ملفات التطبيق، فربما تمكن من قراءة كلمات مرور قاعدة البيانات، وبيانات اعتماد واجهة API، وكلمات مرور SMTP، وأسرار Stripe، ومفاتيح الجلسات، وغيرها من مواد المصادقة.

لذلك أتعامل مع تدوير بيانات الاعتماد باعتباره جزءًا من عملية التنظيف. ينبغي تغيير كلمات مرور قاعدة البيانات. وينبغي تغيير كلمات مرور لوحة تحكم الاستضافة. كما ينبغي مراجعة بيانات اعتماد SSH. وينبغي إعادة إنشاء مفاتيح API عند الاقتضاء. كذلك ينبغي استبدال بيانات اعتماد البريد الإلكتروني إذا كان التطبيق يخزنها.

يستحق إعداد البيئة اهتمامًا خاصًا. إذ تخزن العديد من تطبيقات PHP القيم الحساسة داخل ملفات .env أو ملفات الإعداد. قد يحتوي إعداد نموذجي على شيء مشابه لما يلي:

DB_HOST=localhost
DB_DATABASE=production
DB_USERNAME=website_user
DB_PASSWORD=replace_this_password

STRIPE_SECRET_KEY=replace_this_key
OPENAI_API_KEY=replace_this_key

ينبغي ألا تكون هذه الملفات متاحة مطلقًا عبر خادم الويب العام. فإذا كان بإمكان شخص ما زيارة https://example.com/.env وتنزيل ذلك الملف، فهذا يعني أن التطبيق يعاني من مشكلة خطيرة في الإعداد.

على Apache، أحظر صراحةً الوصول إلى الملفات الحساسة.

<FilesMatch "^(\.env|\.git|composer\.(json|lock)|package(-lock)?\.json)$">
    Require all denied
</FilesMatch>

لا يحل هذا محل بنية المجلدات الصحيحة، لكنه يمنحك طبقة حماية إضافية.

أبقِ الإعدادات الحساسة خارج جذر الويب العام

من أقوى التحسينات المعمارية التي يمكنك إجراؤها فصل أسرار التطبيق عن الملفات المتاحة للعامة. ومن الناحية المثالية، ينبغي أن يحتوي دليل الويب العام فقط على الملفات التي تحتاج فعلًا إلى أن تكون قابلة للوصول من المتصفح.

بدلًا من تخزين بيانات اعتماد قاعدة البيانات داخل مسار مثل:

/public_html/config.php

أفضل استخدام مسار أقرب إلى:

/home/account/private/config.php
/home/account/public_html/index.php

يمكن للتطبيق تضمين ملف الإعدادات الخاص داخليًا، لكن Apache لا يستطيع تقديمه مباشرةً لأنه يقع خارج جذر المستندات.

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

تعطيل قوائم الأدلة

تُعد فهرسة الأدلة مصدرًا آخر غير ضروري لكشف المعلومات. فإذا لم يحتوِ دليل ما على ملف فهرس، فقد تعرض بعض تهيئات Apache محتويات ذلك الدليل. ويمكن للمهاجم استخدام تلك القائمة لاكتشاف أسماء الملفات، وأرشيفات النسخ الاحتياطية، والبرامج النصية، وهياكل الأدلة الداخلية.

أعطّل فهارس الأدلة على مستوى التطبيق بالكامل.

Options -Indexes

لا يوجد عادةً سبب يدعو تطبيق ويب عاديًا إلى كشف بنية أدلته للزوار المجهولين.