أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

ReDoS بالعربي: الـ Regex اللي وقّف Cloudflare 27 دقيقة

📅 ١٩ أبريل ٢٠٢٦⏱ 6 دقائق قراءة
ReDoS بالعربي: الـ Regex اللي وقّف Cloudflare 27 دقيقة

سطر regex واحد ممكن يخلّي سيرفرك يصرف 100% CPU لدقائق على input طوله 30 حرف فقط. ده مش سيناريو نظري — ده اللي حصل لـ Cloudflare في 2 يوليو 2019 وفصل جزء كبير من الإنترنت 27 دقيقة كاملة. المقال ده هيوريك بالظبط ليه بيحصل، وإزاي تمنعه قبل ما يحصلك.

ReDoS: لما سطر Regex واحد بيقفل السيرفر

شاشة سوداء عليها كود برمجي بالأحمر يمثّل regex كارثي أوقف السيرفر

المشكلة باختصار

الـ ReDoS (Regular Expression Denial of Service) هو هجوم أو خطأ بسيط في كتابة regex بيخلّي الـ engine يدخل في عدد محاولات أسي (exponential) بدل ما يرجّع نتيجة في الوقت الطبيعي. الكود اللي بيشتغل في 2ms على input نضيف، بياخد 30 ثانية أو أكتر لما الـ input يبقى مصمم مخصوص.

مثال بسيط لأي مبتدئ: قصة رف المطابخ

تخيّل معاك رف فيه 30 علبة، وبتدور على علبة مكتوب عليها "ملح". الطريقة المنطقية: تبص على كل علبة مرة واحدة. لو لقيتها، توقف. لو خلصت الـ 30 علبة، تستنتج إنها مش موجودة. بالظبط 30 محاولة.

طيب تخيّل إن صاحب المحل غبي شوية. بدل ما يكتفي بالمحاولة الأولى، لما ميلاقيش الملح هو بيقول: "يمكن أنا بصيت بالترتيب الغلط". فبيعيد، بس المرة دي يقلب العلبتين الأولانيتين، يدور تاني. مفيش؟ يقلب العلب التلاتة الأولانيين، يدور تاني. ومع كل فشل، بيجرّب توليفة جديدة من ترتيب العلب.

عدد التوليفات الممكنة لـ 30 علبة = 2^30، يعني أكتر من مليار محاولة. هو ده بالظبط اللي بيحصل جوّا الـ regex engine لما يقابل catastrophic backtracking.

التفسير العلمي الدقيق: Catastrophic Backtracking

معظم الـ regex engines في JavaScript و Python و Java و .NET و PHP بتشتغل بطريقة اسمها NFA with backtracking. يعني الـ engine بيبني Nondeterministic Finite Automaton ويجرّب كل مسار ممكن لحد ما يلاقي match (أو يفشل).

المشكلة بتظهر لما يبقى عندك quantifier متداخل مع quantifier تاني، زي (a+)+ أو (.*)+. الـ engine هنا عنده أكتر من طريقة عشان يقسّم نفس الـ input بين الجروبات الداخلية والخارجية. لو الـ input في آخره حرف بيمنع الـ match، الـ engine بيرجع ويجرّب كل التوزيعات الممكنة قبل ما يستسلم. عدد المسارات = O(2^n) حيث n طول الـ input.

الـ engines المحصّنة (زي Google RE2 و Rust's regex crate) بتستخدم Deterministic Finite Automaton — بتديك ضمان O(n) دايماً، بس بتتنازل عن features زي \1 backreferences و lookaheads.

كود تقدر تجرّبه دلوقتي

شغّل الكود ده في Node.js وشوف بعنيك الفرق بين input نضيف وinput خبيث:

JavaScript
// ملف: redos-demo.js
const evilPattern = /^(a+)+$/;

function measure(input, label) {
  const start = Date.now();
  evilPattern.test(input);
  const elapsed = Date.now() - start;
  console.log(`${label}: ${elapsed}ms`);
}

// Input نضيف — match ناجح وسريع
measure("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "match ناجح (30 حرف)");

// Input خبيث — آخر حرف مختلف، الـ engine هيحاول كل تركيبة
measure("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!", "match فاشل (30 حرف + !)");
// على لاب توب عادي: > 30,000ms

المتوقّع: الأول أقل من 1ms، التاني بيوقف الـ thread أكتر من نص دقيقة. الفرق مش linear، ده exponential — كل حرف "a" تضيفه في الـ input الخبيث بيضاعف الزمن.

قصة Cloudflare: 27 دقيقة وقف فيها نص الإنترنت

في 2 يوليو 2019 الساعة 13:42 UTC، رفع مهندس في Cloudflare قاعدة WAF جديدة لمنع هجمات XSS. القاعدة دي كان فيها regex بالشكل التقريبي .*.*=.*. المعنى الحرفي: "طابق أي شيء، بعدين أي شيء، بعدين علامة يساوي، بعدين أي شيء".

لما الـ WAF استقبلت request جواها محتوى طويل من غير =، الـ regex engine (PCRE) دخل في backtracking كارثي. نتيجة: كل الـ CPUs في كل datacenters Cloudflare وصلت 100% في خلال دقيقة واحدة. 502 errors لـ 27 دقيقة على مليارات الطلبات حول العالم. مواقع زي Discord و Coinbase و Feedly وقعت بالتبعية.

الحل اللي اعتمدته Cloudflare بعدها: التحوّل لـ RE2 اللي بيدّي ضمان linear time، ومراجعة يدوية لكل 3,868 قاعدة WAF للتأكد إن مفيش فيها pattern قابل للـ backtracking.

غرفة سيرفرات فيها كابلات شبكة مضيئة ترمز لارتفاع استهلاك CPU بسبب ReDoS

4 طرق عملية لحماية نفسك

  1. اعيد كتابة الـ pattern. استبدل (a+)+ بـ a+. استبدل (.*a)+ بـ ([^a]*a)+. الفكرة: امنع الـ engine من إنه يقسّم نفس الحرف بين جروبين.
  2. استخدم atomic groups أو possessive quantifiers. الصيغة (?>...) بتمنع الـ backtracking داخل الجروب. متوفرة في Java و PCRE و Python 3.11+.
  3. حط timeout على تنفيذ الـ regex. في Python استخدم signal.alarm أو مكتبة regex اللي بتقبل parameter اسمه timeout. في Node.js، شغّل الـ regex في worker thread مع terminate() بعد ثانية.
  4. بدّل الـ engine. استخدم re2 في Python (pip install google-re2) أو Rust regex crate. دول بيضمنوا linear time.

كود Python بيوضح طريقة 3 و 4:

Python
import re2  # pip install google-re2

# آمن ضد ReDoS بضمان engine level
pattern = re2.compile(r"^(a+)+$")
result = pattern.match("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!")
# بيرجع None في مللي ثواني بدل الدقائق

trade-offs لازم تعرفها قبل ما تبدّل

لو اخترت تبدّل لـ RE2، الـ trade-off صريح: هتكسب ضمان O(n) على كل input، لكن هتخسر backreferences (\1, \2) و lookaheads/lookbehinds. في تطبيقات validation بسيطة زي emails أو slugs ده مش هيأثر. في parsers معقّدة بتعتمد على backreferences، هتحتاج refactor.

لو اخترت إعادة كتابة الـ pattern، بتكسب توافق كامل مع كل features الـ regex، بس الـ trade-off إنك محتاج تراجع يدوي، وخطأ بشري واحد ممكن يرجّع المشكلة. الحل الوسطي: استخدم linter زي safe-regex (لـ JS) أو regexploit لكشف الـ patterns الخطيرة قبل الـ deploy.

متى ميبقاش ReDoS خطر عليك

لو الـ regex بتاعتك بتشتغل على input جاي من مصدر موثوق (enum من backend، أو قيم ثابتة من config)، الـ ReDoS مش مخاطرة حقيقية. التركيز يبقى على نقاط الـ user input: form fields، query params، webhook payloads، HTTP headers. كمان لو الـ input محدود الطول (مثلاً username أقصاه 20 حرف)، الـ exponential هيفضل في حدود آمنة عمليًا — بس دي حماية بالمصادفة مش بالتصميم.

الخطوة التالية

افتح مشروعك دلوقتي وابحث بـ grep عن الأنماط دي: (.*)+, (.+)+, (a|a)+, (a|ab)+, وأي quantifier داخل quantifier. شغّل عليهم linter زي safe-regex:

Bash
npm install -g safe-regex
safe-regex "^(a+)+$"
# output: false  →  الـ pattern خطير

لو لقيت pattern واحد راجع، ابدأ بيه وحدّه. أهم حاجة: مش مطلوب منك تبدّل الـ engine بالكامل النهارده، المطلوب تعرف فين بالظبط الـ regex الخطير وتحطّ عليه timeout كحد أدنى.

المصادر

  • Cloudflare Engineering Blog — Details of the Cloudflare outage on July 2, 2019
  • OWASP — Regular expression Denial of Service (ReDoS)
  • Snyk Learn — ReDoS Tutorial & Examples
  • Sonar — A comprehensive guide to the dangers of Regular Expressions in JavaScript
  • Wikipedia — ReDoS
  • Google RE2 — Safe regex engine on GitHub

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة