تخطَّ إلى المحتوى

تحليل تقني معمّق

تصليب Apache ضد هجمات DDoS: اختيار MPM وmod_reqtimeout والحدود لكل مصدر

آخر تحديث: أغسطس 2026 · اختيار MPM وmod_reqtimeout وmod_qos وmod_evasive · زمن القراءة ~18 دقيقة

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

القرار الأول في Apache هو اختيار MPM. وحدة prefork تنفق عملية كاملة لكل اتصال وهي مكشوفة أمام Slowloris؛ ووحدة event لا تفعل ذلك وهي أصمد بكثير. وفوق الوحدة الصحيحة يغلق mod_reqtimeout هجمات الطلب البطيء، ويحدّ mod_qos من الاتصالات لكل مصدر، ويمنع mod_evasive فيضان الطلبات. كلٌّ منها توجيه له عدّاد، ويُقاس على أساسك أنت.

يصلّب هذا الدليل Apache httpd نفسه ضد الجزء المستنزِف للاتصالات والطلبات من هجوم DDoS، دون أي جهاز أمامه. وخلافاً لـ nginx، صمود Apache ليس معطى مسبقاً. يقرّره أولاً اختيار تتخطّاه أكثر الأدلة: وحدة المعالجة المتعدّدة (MPM). فإن أخطأت فيه لن ينقذك ضبط الوحدات أدناه، وإن أصبته أدّت الوحدات عملها.

كل توجيه يأتي بوحدته وقيمته والعدّاد الذي يُظهر عمله. والقيم نقاط بداية تُقاس على حركتك أنت.

أشكال الهجوم وآليات Apache التي تجيب عنها
الجهازشكل الهجومآلية Apacheالتحقق
رأس بطيء / جسم بطيء (Slowloris)mod_reqtimeout RequestReadTimeout؛ وحدة eventنسبة 408 في سجل الوصول؛ لوحة server-status
اتصالات كثيرة لكل مصدرmod_qos QS_SrvMaxConnPerIPserver-status العمّال المشغولون؛ عدّادات mod_qos
فيضان طلبات من مصادر قليلةmod_evasive DOSPageCount / DOSSiteCountنسبة 403؛ سجل mod_evasive
استنزاف العمّالMaxRequestWorkers, ThreadsPerChild (وحدة event)server-status: المشغول مقابل الخامل
إساءة الطلبات الضخمةLimitRequestBody, LimitRequestFields, LimitRequestLineنسبة 413 / 400 في سجل الوصول

الصف الأول يحدّد البقية. على prefork يستنزف Slowloris العمليات قبل أن يعمل أي حدّ آخر، فلذلك يأتي اختيار MPM قبل ضبط الوحدات. ولا ينفع شيء منها متى ملأ الهجوم الوصلة أمام Apache.

0. الأساس أولاً: شغّل لوحة النتائج

الحالة الحيّة في Apache هي لوحة نتائج mod_status. فعّلها مقصورةً على localhost، وشغّل الحالة الموسّعة.

ExtendedStatus On
<Location "/server-status">
    SetHandler server-status
    Require ip 127.0.0.1
</Location>
# لوحة نتائج العمّال: أعداد بحسب الحالة
curl -s http://127.0.0.1/server-status?auto | grep -E 'BusyWorkers|IdleWorkers|Total Accesses'

# عدد الطلبات لكل عميل من سجل الوصول، أسبوع عادي
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head

قيمة BusyWorkers قياساً على سقف MaxRequestWorkers، ومعدّل كل عميل من السجل، هما الأساس الذي تُقاس عليه كل عتبة أدناه.

1. وحدة MPM: القرار الذي يسبق كل شيء

هذا هو القسم الذي يفصل Apache صامداً عن Apache مكشوف. انظر أي وحدة MPM فعّالة.

apachectl -V | grep -i 'Server MPM'
# أو
apache2ctl -M | grep mpm

إن كانت prefork، فهي أول ما يُغيَّر ما لم تفرضها وحدة غير آمنة على مستوى الخيوط. تشغّل prefork عمليةً لكل اتصال، فيستنزف هجوم Slowloris مجمّع العمليات ببضعة آلاف من الاتصالات البطيئة. وتستخدم event الخيوط ومستمعاً مخصّصاً يتسلّم اتصالات keep-alive والإغلاق المتباطئ، فيكلّف الاتصال البطيء خانة خيط لا عملية.

والسبب المعتاد لبقاء الخادم على prefork هو mod_php. ونقل PHP إلى PHP-FPM يفتح لك تشغيل event وهو أكبر مكسب صمود هنا.

# ضبط mpm_event — السعة الكلية = ServerLimit * ThreadsPerChild
<IfModule mpm_event_module>
    StartServers            4
    ServerLimit             16
    ThreadsPerChild         64
    MaxRequestWorkers       1024      # ServerLimit * ThreadsPerChild
    MaxConnectionsPerChild  10000     # إعادة تدوير لتحديد نمو الذاكرة
</IfModule>
# تأكيد الوحدة العاملة والسقف
apachectl -V | grep -i mpm
curl -s http://127.0.0.1/server-status?auto | grep -E 'BusyWorkers|IdleWorkers'

قيمة MaxRequestWorkers هي السقف الصلب لعدد الطلبات المتزامنة. اضبطها على ما تحتمله ذاكرتك لا أعلى، لأن تجاوز الذاكرة تحت الحمل انقطاعٌ بذاته.

2. mod_reqtimeout: الجواب المباشر على Slowloris

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

<IfModule mod_reqtimeout_module>
    # الرأس: 20s بداية، تمتد إلى 40s بحدّ أدنى 500 بايت/ث
    # الجسم:  20s، تمتد بحدّ أدنى 500 بايت/ث
    RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>
# الطلبات البطيئة المُسقَطة تظهر بالرمز 408 في سجل الوصول
awk '$9==408' /var/log/apache2/access.log | wc -l

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

3. mod_qos: الاتصالات لكل مصدر وإجمالاً

وحدة mod_qos هي طبقة تزامن الاتصالات والإنصاف. وهي أقرب مقابل في Apache لتوجيه limit_conn في nginx.

<IfModule mod_qos_module>
    QS_SrvMaxConn            2048     # إجمالي الاتصالات المتزامنة
    QS_SrvMaxConnPerIP       50       # لكل عنوان مصدر
    QS_SrvMaxConnClose       70%      # أوقف keep-alive فوق هذا الحمل لتحرير الخانات
    QS_SrvMinDataRate        150 1200 # حدّ أدنى بايت/ث يرتفع تحت الحمل — قطع Slowloris ثانٍ
</IfModule>

توجيه QS_SrvMaxConnClose دقيق ونافع. فوق الكسر المحدّد من المجمّع يكفّ Apache عن احترام keep-alive فتتحرّر الاتصالات أسرع. ويفرض QS_SrvMinDataRate حدّاً أدنى للخرج يرتفع كلما امتلأ الخادم، فيطرح أبطأ الاتصالات في اللحظة التي تشحّ فيها الخانات بالضبط.

# mod_qos يعرض عدّاداته الخاصة
curl -s 'http://127.0.0.1/server-status?auto' | grep -i qos

4. mod_evasive: حجب فيضان الطلبات

يعدّ mod_evasive الطلبات لكل مصدر في نافذة قصيرة، ويحجب مؤقتاً المصدر الذي يتجاوز العتبة.

<IfModule mod_evasive20_module>
    DOSHashTableSize    3097
    DOSPageCount        5        # الصفحة نفسها، لكل مصدر، لكل فترة
    DOSSiteCount        50       # أي صفحة في الموقع، لكل مصدر، لكل فترة
    DOSPageInterval     1        # ثوانٍ
    DOSSiteInterval     1
    DOSBlockingPeriod   30       # مدة الحجب، ثوانٍ
    DOSLogDir           /var/log/apache2/evasive
</IfModule>
# المصادر المحجوبة تُسجَّل ويعود لها الرمز 403
awk '$9==403' /var/log/apache2/access.log | wc -l
ls /var/log/apache2/evasive/    # ملف قفل لكل مصدر محجوب حالياً

أبقِ DOSBlockingPeriod قصيراً في البداية. فحجب طويل مع إيجابية كاذبة يُخرج مستخدماً حقيقياً طوال المدة كلها. وكأي حدّ هنا، راقب ما يلتقطه قبل أن تثق به.

5. حدود حجم الطلب وحقوله

أغلق سطح الطلبات الضخمة الذي يمكنه استنزاف الذاكرة بمعزل عن عدد الاتصالات.

LimitRequestBody      10485760    # 10 MB
LimitRequestFields    100         # أقصى عدد ترويسات
LimitRequestFieldSize 8190        # أقصى حجم ترويسة
LimitRequestLine      8190        # أقصى طول لسطر الطلب
Timeout               60          # مهلة الإدخال/الإخراج العامة، أقل من 300 الافتراضية
KeepAliveTimeout      5           # خمول keep-alive قصير
MaxKeepAliveRequests  100
# الطلبات الضخمة: 413 (جسم) و400 (رأس/سطر)
awk '$9==413 || $9==400' /var/log/apache2/access.log | wc -l

القيمة الافتراضية لـ Timeout وهي 300 ثانية سخيّة جداً لخادم عام. وخفضها وحده تخفيف Slowloris هادئ لكنه حقيقي.

6. ضبط عنوان العميل خلف وسيط

كل حدّ لكل مصدر، أي mod_qos وmod_evasive، يُفهرَس على عنوان العميل. وخلف وسيط يكون هذا عنوان الوسيط ما لم يُصحَّح بـ mod_remoteip.

<IfModule mod_remoteip_module>
    RemoteIPHeader X-Forwarded-For
    RemoteIPTrustedProxy 10.0.0.0/8 172.16.0.0/12
</IfModule>
# سجّل العميل الحقيقي لا الوسيط
LogFormat "%a %l %u %t \"%r\" %>s %b" combined_realip
# إن أعاد هذا 1 فكل طلب يُنسَب إلى الوسيط والحدود لكل مصدر بلا معنى
awk '{print $1}' /var/log/apache2/access.log | sort -u | wc -l

الإشارات التي تُربط بالمراقبة

# 1. العمّال المشغولون / السقف — إشباع المجمّع
curl -s http://127.0.0.1/server-status?auto | awk -F': ' '/BusyWorkers/{print $2}'
# 2. نسبة 408 — تفعّل مهل الطلب البطيء
awk '$9==408' /var/log/apache2/access.log | wc -l
# 3. نسبة 403 — حجب mod_evasive
awk '$9==403' /var/log/apache2/access.log | wc -l
# 4. جدار الحالة R في لوحة النتائج — توقيع Slowloris
curl -s http://127.0.0.1/server-status | grep -o 'R' | wc -l

جدار من العمّال في الحالة R (قراءة) توقيعٌ لا يخطئ لـ Slowloris. والعمّال المشبعون في الحالة W (كتابة) فيضان طلبات. يظهر الاثنان مختلفين في لوحة النتائج ويستدعيان حدوداً مختلفة.

الحدّ الصادق لتصليب Apache

كل ما هنا يدافع عن استنزاف حالة الاتصال ومعدّل الطلبات عند حافة التطبيق. وحالتان تقعان خارجه.

الأولى امتلاء الوصلة. الحجم الذي يملأ الأنبوب لا يصل إلى Apache أصلاً، ولا تغيّر ذلك أي وحدة MPM أو أي وحدة.

أين تتوقف الطبقة داخل المنشأة عن أن تنفع وصلة الوصول لديك: 10 غيغابت/ث الخط مُشبع أصلاً — الطبقة العليا فقط الجهاز داخل المنشأة يخفّف 2 غيغابت/ث 8 غيغابت/ث 25 غيغابت/ث 120 غيغابت/ث 1 تيرابت/ث+ حجم الهجوم (مقياس لوغاريتمي)
تحت الوصلة لحدود Apache نصيب؛ وفوقها لا معنى لأي توجيه.

والثانية طبقة النواة تحت Apache: طوابير SYN، وconntrack، وموصِّفات الملفات. يمرّ الطلب بهذه الطبقة قبل أن يراه httpd، ويتناولها دليل تصليب Linux. ويفترض تصليب Apache أن تلك الطبقة قائمة. وفوق الوصلة يكون الجواب طبقة الشبكة، ويُبقي Apache حافة التطبيق قائمة حتى ذلك الحين.

ترتيب التطبيق

  1. فعّل mod_status؛ سجّل أساس أسبوع.
  2. انظر إلى الوحدة MPM. إن كانت prefork فانقل PHP إلى PHP-FPM وانتقل إلى event، قبل أي شيء.
  3. اضبط سعة وحدة event على ما تحتمله الذاكرة.
  4. أضِف mod_reqtimeout؛ راقب نسبة 408.
  5. صحّح mod_remoteip إن وُجد وسيط، قبل الحدود لكل مصدر.
  6. أضِف mod_qos وmod_evasive؛ أبقِ مدد الحجب قصيرة حتى تثق بها.
  7. اربط الإشارات الأربع بالمراقبة.

الخطوة الثانية ليست اختيارية ولا يتغيّر موضعها. على prefork، كل حدّ تحتها يُطبَّق على خادم يستطيع Slowloris استنزافه رغم ذلك.

أسئلة متكررة

أي وحدة MPM أشغّل من أجل الصمود أمام DDoS؟
وحدة event في كل الحالات تقريباً. تشغّل prefork عملية لكل اتصال، فبضعة آلاف من الاتصالات البطيئة تستنزف مجمّع العمليات، وهذه هي نتيجة Slowloris الكلاسيكية. وتوجد prefork أساساً من أجل وحدات غير آمنة على مستوى الخيوط مثل mod_php القديمة. أمّا event وworker فتستخدمان الخيوط ومستمعاً مخصّصاً يتسلّم اتصالات keep-alive، فيكلّف الاتصال البطيء خانةً واحدة لا عملية كاملة. وإن كنت على prefork بسبب mod_php وحده، فنقل PHP إلى PHP-FPM يتيح لك الانتقال إلى event وهو أكبر مكسب صمود متاح هنا.
هل يكفي mod_reqtimeout وحده ضد Slowloris؟
على event يكاد يكفي، وعلى prefork يساعد لكن الوحدة تظل تحدّك. يحدّ RequestReadTimeout من المدة التي يستغرقها العميل لإرسال سطر طلبه وترويساته، فيُسقَط الاتصال الذي يرسل الترويسات نقطةً نقطة عند انتهاء المدة بدل إبقائه مفتوحاً. هذا هو الجواب المباشر على Slowloris. لكن على prefork يظل كل اتصال محتجَز عمليةً كاملة حتى تنتهي المدة، فيجب أن تكون المدة قصيرة ويبقى مجمّع العمليات هو السقف. وعلى event تكون المدة نفسها أشدّ فاعلية، لأن كلفة الاتصال المعلّق كانت منخفضة أصلاً.
mod_evasive أم mod_qos، أيّهما يلزمني؟
كلٌّ منهما يعالج شكلاً مختلفاً، وكثير من المواقع تشغّل الاثنين. يعدّ mod_evasive طلبات الصفحة والموقع لكل مصدر في نافذة قصيرة، ويحجب مؤقتاً المصدر الذي يتجاوز العتبة؛ فهو دفاع ضد فيضان الطلبات. ويحدّ mod_qos من الاتصالات المتزامنة لكل مصدر وإجمالاً، ويمكنه إعطاء أولوية للحركة المعروفة السلامة تحت الحمل؛ فهو دفاع عن تزامن الاتصالات والإنصاف. وينشر mod_evasive أسرع، وmod_qos أقدر وضبطه أكثر جهداً. ولا يغني أيٌّ منهما عن الوحدة الصحيحة وmod_reqtimeout تحتهما.
أي قيم أضبط لـ RequestReadTimeout؟
ابدأ بمدة رأس بعشرات الثواني تضيق مع وصول البايتات، ومدة جسم أقصر، ثم اقرأ نسبة 408. الصيغة المتدرّجة، أي مهلة أولية أطول تضيق كلما وصلت البيانات، تميّز عميلاً بطيئاً لكنه حقيقي على وصلة رديئة عن عميل Slowloris يرسل بايتاً واحداً في كل مرة. إن شدّدتها أكثر من اللازم قطعت مستخدمي الجوال على الوصلات السيئة، وإن أرخيتها بقيت الهجمات البطيئة حيّة. ونسبة 408 قياساً على أساسك تدلّك إلى أي اتجاه تتحرّك.
كيف أراقب Apache أثناء هجوم؟
عبر mod_status مع ExtendedStatus مفعّلاً. تُظهر لوحة النتائج حالة كل عامل: قراءة (R)، إرسال (W)، keep-alive‏ (K)، إغلاق (C). فيظهر هجوم Slowloris جداراً من العمّال عالقين في الحالة R، ويظهر فيضان الطلبات عمّالاً مشبعين في الحالة W. اقصر server-status على localhost، وراقب عدد العمّال المشغولين مقابل الخاملين، واربط عدد المشغولين قياساً على MaxRequestWorkers بنظام المراقبة. ومتى اقترب المشغول من السقف كان المجمّع هو عنق الزجاجة.
هل تُوقف هذه الإعدادات هجوماً حجمياً؟
لا. إن ملأ الهجوم الوصلة أمام الخادم فإن Apache لا يستقبل الطلبات أصلاً ولا ينطبق أي إعداد وحدة أو توجيه. كل ما هنا يدافع عن استنزاف حالة الاتصال ومعدّل الطلبات عند حافة التطبيق. أمّا الحجم فوق سعة الوصلة فمشكلة طبقة الشبكة ولا يُحلّ في httpd.conf.

النشر: أغسطس 2026

يُحدَّث هذا الدليل كلما طرح المصنّعون طرازات وشروط ترخيص جديدة. كيف نقارن بين المصنّعين