Cloud · DevOps · PHP Security · Web Runtimes

FrankenPHP 1.13.5: أغلق تنفيذ الملفات المرفوعة بأمان

يعالج FrankenPHP 1.13.5 سبع عشرة ثغرة. قيّم تعرض الرفع وWorkers، وأعد البناء، وتحقق من المسارات والأدلة بأمان.

المسار المرتبطالسحابة وDevOps وKubernetes
فني يستخدم حاسوبًا محمولًا بجوار رف خوادم، في تمثيل لتحديث FrankenPHP الأمني والتحقق منه بصورة مضبوطة
e

يُعد FrankenPHP 1.13.5 إصدارًا أمنيًا يعالج 17 ثغرة. أخطرها قد يجعل ملفًا مرفوعًا غير PHP يُنفذ كشيفرة PHP عندما يسبب مسار مصاغ خصيصًا اختلافًا بين منطق التوجيه وتقسيم المسار في خادم PHP. إذا كنت تشغّل FrankenPHP 1.13.4 أو أقدم، فأعد بناء كل الصور على 1.13.5، وأبقِ الملفات المرفوعة خارج جذر الويب، واستبدل كل النسخ العاملة، ثم تحقق من التوجيه وعزل Workers قبل إعلان اكتمال المعالجة.

نُشر الإصدار الرسمي 1.13.5 في 5 نوفمبر 2026. يميز هذا الدليل بين ما وثقه المشروع والتوصيات الهندسية لفرق المنصات. تتضمن النشرات الرسمية مادة إثبات مفهوم، لكن مصادر المشروع المذكورة هنا لا تعلن استغلالًا نشطًا أو اختراقًا مؤكدًا. رؤية محاولة في السجل لا تثبت تنفيذ الشيفرة.

الإجابة أولًا

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

  1. احصر إصدار FrankenPHP الفعلي وبصمة الصورة على كل عقدة وPod وحاوية؛
  2. انقل الملفات التي يتحكم فيها المستخدم — أو أكد وجودها — خارج جذر المستندات؛
  3. أعد بناء القطع الثابتة على FrankenPHP 1.13.5 أو أحدث؛
  4. استبدل جميع النسخ، بما فيها Workers طويلة العمر؛
  5. تحقق من أن مسارات السكربت غير الصالحة تعيد 404، ومسارات الرفع تبقى ثابتة، ومصدر PHP لا يُعرض، وحالة الطلب لا تعبر بين الطلبات؛
  6. احتفظ بأدلة النشر وراجع الطلبات التاريخية المشبوهة من دون مساواة المحاولة بالاختراق.

ما تثبته المصادر الرسمية

يصف المشروع FrankenPHP 1.13.5 بأنه إصدار أمني يعالج 17 ثغرة. كما يحدث الإصدار مكونات مضمّنة إلى Caddy 2.11.9 وMercure 1.1.6، ويوصي بقوة بالترقية.

تؤثر النشرة الأعلى خطورة، GHSA-j99q-3wr8-xj43، في FrankenPHP حتى 1.13.4، وأُصلحت في 1.13.5. توثق النشرة ارتباكًا في المسار داخل php_server: إذا استطاع المهاجم وضع ملف أو مسار يختاره تحت جذر المستندات، فقد يجعل طلب يحتوي مقطعًا يوحي بأنه PHP ملفًا لاحقًا غير PHP هو الملف المختار والمنفذ. يرفض المعالج المصحح مسار السكربت غير الصالح بحالة 404. تمنح النشرة CVSS 7.5 ولا تعيّن CVE.

وتهم نشرتان مرتبطتان بتشغيل Workers:

  • تؤثر GHSA-v7hf-4gqv-hf8p في الإصدارات من 1.8.0 إلى 1.13.4. قد يؤدي جمع قاعدة match لـWorker مع خادم الملفات المدمج إلى عرض مصدر PHP بدل تنفيذه. يعالج 1.13.5 المشكلة.
  • تؤثر GHSA-8qcf-v46r-g2mc في الإصدارات حتى 1.13.4. في أنماط تطبيق محددة، قد يتسرب خرج أو Headers أو Cookies تولدت متأخرًا من طلب سابق إلى الطلب التالي الذي يخدمه Worker نفسه. تقول النشرة إن الوضع التقليدي Classic غير متأثر.

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

حقيقة موثقة: نشر المشروع النشرات والإصدار المصحح. ادعاء المشروع: يعالج الإصدار المشكلات المدرجة وينبغي تثبيته. تحليل هندسي: تعتمد الأولوية الفعلية على قدرة المهاجم على الكتابة تحت جذر المستندات، ووصول مسارات الرفع إلى php_server، ووجود إعدادات أو سلوك دورة حياة خاص بـWorkers.

جدول قرار التعرض

حالة التشغيلالأولويةالإجراء الفوري
FrankenPHP 1.13.4 أو أقدم ويمكن لملفات يتحكم فيها المستخدم الوصول إلى جذر المستنداتأولوية تشغيلية حرجةاعزل الملفات، وقيّد التوجيه، وأعد البناء على 1.13.5، وراجع أدلة الطلبات والعمليات
php_server متاح لكن الرفع يُخزن خارج جذر المستنداتعاليةحدّث بسرعة وتحقق من عدم وجود استيراد أو Cache أو فك أرشيف يكتب داخل الجذر
وضع Worker يستخدم match مع خادم الملفات المدمجعاليةحدّث؛ وحتى ذلك الحين عطّل خادم الملفات على المسار أو أزل نمط المطابقة الخطر
قد يصدر Worker خرجًا من Destructor أو Error handler أو Garbage collection بعد الاستجابةعالية للسريةحدّث، ودوّر Workers المتأثرة، واختبر العزل بين الطلبات
الوضع التقليدي فقط ولا توجد كتابة يتحكم فيها مهاجمما زال التحديث مطلوبًاتسرب Worker لا ينطبق، لكن مشكلة المسار وإصلاحات 1.13.5 الأخرى تحتاج مراجعة
لا تستطيع إثبات الإصدار أو الإعدادعامله كتعرضالتقط إصدار التشغيل وبصمة الصورة وإعداد Caddy الفعلي بدل التخمين
يربط دليل المعالجة إصدار التشغيل والصورة الثابتة والمسارات الفعلية ودورة Worker واختبارات التحقق السلبية.
يربط دليل المعالجة إصدار التشغيل والصورة الثابتة والمسارات الفعلية ودورة Worker واختبارات التحقق السلبية. اضغط لعرض أكبر

اعثر على كل نسخة عاملة

وجود Tag في مستودع ليس دليل تشغيل. استعلم عن الملف التنفيذي داخل كل وحدة حية، واربط النتيجة بمعرف الصورة المنشورة.

على Host مستقل:

frankenphp version
systemctl status frankenphp --no-pager
systemctl cat frankenphp

في Docker، سجل مرجع الصورة وبصمتها والإصدار من داخل الحاوية:

docker inspect --format '{{.Config.Image}} {{.Image}}' <container>
docker exec <container> frankenphp version

في Kubernetes، اجمع مراجع الصور ومعرفاتها الثابتة، ثم تحقق من الملف التنفيذي في Pods ممثلة لكل Workload وRevision:

kubectl get pods -A -o custom-columns='NS:.metadata.namespace,POD:.metadata.name,IMAGE:.spec.containers[*].image,IMAGE_ID:.status.containerStatuses[*].imageID'
kubectl exec -n <namespace> <pod> -- frankenphp version

وابحث في صور CI الأساسية، وقيم Helm، وCompose، ووحدات systemd، وBuildpacks، وقوالب التعافي، والنسخ الخاملة. إصلاح النشر الرئيسي مع إبقاء صورة Rollback ضعيفة ليس معالجة مكتملة.

احتواء الخطر قبل إعادة البناء

أقوى ضبط تعويضي في النشرة الرئيسية معماري: خزّن الملفات المرفوعة خارج جذر المستندات. وإذا كان التطبيق سيخدمها، فاستخدم مسارًا ثابتًا أو Object storage لا يمكنه دخول معالج PHP.

حتى يكتمل النشر:

  • امنع الكتابة إلى جذر المستندات إلا من عملية البناء والإصدار؛
  • وجّه بادئات الرفع مباشرة إلى تخزين ثابت، ولا تمررها إلى php_server؛
  • ارفض مقاطع المسار المتداخلة المشبوهة التي توحي بـPHP والفواصل المشفرة غير المعتادة عند الحافة بعد اختبار المسارات الشرعية؛
  • امنع فك أرشيف غير موثوق داخل أي مجلد مخدوم؛
  • لحالة كشف المصدر، استخدم file_server off على مسار Worker المتأثر أو أزل إعداد match الخطر، كما توصي النشرة؛
  • ارفع مراقبة سلوك عمليات PHP الفرعية والاتصالات الصادرة وتغير الملفات.

هذه ضوابط مؤقتة. لا تستبدل الإصدار المصحح، كما أن file_server off يعالج إعداد كشف المصدر الموثق وليس كل مشكلات 1.13.5.

حدّث باستبدال ثابت

  1. جمّد خط الأساس. احفظ بصمة الصورة الحالية، وخرج frankenphp version، وإعداد Caddy الفعلي، وحصر البيئة، ونتائج صحة ممثلة.
  2. حدّث البناء. اختر قطعة FrankenPHP رسمية بإصدار 1.13.5 أو أحدث ومتوافقة مع إضافات PHP. ثبّت Digest المحلول في الإنتاج، لا Tag قابلًا للتغيير وحده.
  3. أعد بناء التبعيات. أنشئ صورة التطبيق والإضافات وحزم النظام من جديد؛ لا تنسخ ملف FrankenPHP القديم أو مجلد وحدات Caddy إلى الطبقة الجديدة.
  4. افحص ووثّق. أنشئ SBOM، وشغّل ماسح الصور المؤسسي، وتحقق من المصدر وآلية التوقيع أو Provenance المتاحة في سلسلة التوريد.
  5. استخدم Canary آمنًا. أرسل مرورًا مضبوطًا إلى عدد صغير من النسخ الجديدة. اختبر الرفع، ومسارات Front controller، وWorkers، وCache، والمصادقة من دون استخدام الاستغلال العام.
  6. استبدل ولا تكتفِ بإعادة التحميل. أنهِ الحاويات وWorkers القديمة كي لا تبقى عملية قبل الإصلاح. تحقق من كل Pod وعقدة ونسخة Rollback.
  7. رقِّ مع الدليل. أرفق Digest وخرج الإصدار وبصمة الإعداد ونتائج الاختبارات وأوقات النشر بسجل التغيير.

تذكر ملاحظات 1.13.5 أن Caddy حُدث إلى 2.11.9. إذا كنت تبني ملفًا مخصصًا من FrankenPHP/Caddy، فتحقق من مكونات الملف النهائي بدل افتراض أن Tag الصورة قام بكل شيء.

تحقق من دون تسليح الإنتاج

استخدم اختبارات توجيه سلبية وملفات غير ضارة:

الاختبارالنتيجة المتوقعة على النشر المصحح
طلب مسار سكربت غير صالح أو غير موجود مع معلومات مسار إضافية404، ومن دون الارتداد إلى ملف غير PHP
رفع ملف نصي غير ضار عبر المسار الطبيعييُخزن خارج جذر المستندات ويُخدم كمحتوى ثابت فقط
طلب اسم ملف مصدر PHP عبر Worker ومسارات الملفاتلا يُعاد المصدر مطلقًا
إرسال طلبين بعلامات مختلفة عبر Worker نفسه مع تشغيل التنظيف المعتادلا تنتقل Header أو Cookie أو علامة في Body إلى الاستجابة التالية
إرسال قيمة Host غير معروفة في بيئة الاختباريُرفض الطلب أو يوجّه فقط وفق سياسة Host المقصودة
بث Body ببطء في Stagingتمنع المهلات وضوابط التزامن عميلًا واحدًا من استنزاف كل Threads
إعادة التشغيل والتوسيعتبلغ كل نسخة بديلة عن 1.13.5 أو أحدث وعن Digest المعتمد

نفّذ الاختبارات نفسها من Ingress العام ومن مسار خدمة داخلي، لأن الوكلاء قد يعيدون كتابة URI أو Host أو معلومات المسار. التقط الحالة وHeaders وسجلات الخادم. لا ترفع حمولة PHP تنفيذية ولا تعِد تشغيل إثباتات الاستغلال العامة ضد الإنتاج.

مراجعة تاريخية: المحاولة ليست اختراقًا

ابحث في سجلات الوصول وWAF عن مقاطع .php متداخلة، وتكرار متغيرات Path info، وفواصل مشفرة، وUnicode غير معتاد حول لاحقات السكربت، ومسارات رفع يتبعها طلب يشبه التنفيذ، ونجاح ردود لعنصر غير PHP يفترض أن يكون ثابتًا. اربط ذلك مع:

  • سجلات إنشاء الملفات وسلامتها تحت جذر المستندات؛
  • سجلات PHP وCaddy والتطبيق؛
  • أشجار العمليات والعمليات الفرعية غير المتوقعة؛
  • اتصالات DNS والشبكة الصادرة؛
  • الوصول إلى الأسرار وتغييرات المصادقة ومؤشرات الاستمرارية.

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

أفضل الممارسات

  • أبقِ الملفات المرفوعة والمولدة خارج جذر المستندات التنفيذي.
  • اجعل إصدار التشغيل وبصمة الصورة ظاهرين في حصر النشر.
  • عامل Caddyfile الفعلي كقطعة مضبوطة قابلة للمراجعة.
  • استخدم أقل صلاحيات للملفات في عملية FrankenPHP.
  • قيّد زمن Body وحجمه عند Ingress والتطبيق.
  • امنح تطبيقات Worker اختبارات صريحة لدورة الحياة والتنظيف والعزل.
  • احتفظ بقطعة Rollback مختبرة ومصححة كذلك.

أنماط خاطئة وحدود

لا تعلن اكتمال المعالجة لأن Dockerfile تغير، أو Tag يقول “latest”، أو Pod واحد أعيد تشغيله، أو WAF حجب مثالًا واحدًا. لا تجعل نجاح الاستغلال اختبار قبول للإنتاج. لا تستنتج الاختراق من نتيجة Scanner وحدها، ولا تستنتج الأمان من غياب سلسلة محددة في Access logs.

تصف النشرات سلوك البرنامج لا التطبيق كله. قد تضيف آلية التوجيه في Framework، والوكلاء العكسية، وفك الأرشيفات، وVolumes المركبة، ووحدات Caddy المخصصة، وشيفرة Worker تعرضًا لا يغطيه الإعداد الافتراضي. وبالعكس، يقلل فصل كل محتوى المستخدم عن جذر المستندات شرط الثغرة الرئيسية، لكنه لا يلغي تثبيت بقية إصلاحات 1.13.5.

قائمة تنفيذية

  • [ ] حُصرت كل نسخة حية وRollback بالإصدار وDigest.
  • [ ] لا يمكن لملف يتحكم فيه المستخدم أن يُكتب تحت جذر المستندات.
  • [ ] تستخدم قطع البناء FrankenPHP 1.13.5 أو أحدث.
  • [ ] استُبدلت كل الحاويات وWorkers القديمة.
  • [ ] تعيد مسارات السكربت غير الصالحة 404.
  • [ ] لا تدخل مسارات الرفع إلى معالج PHP.
  • [ ] لا تعرض مسارات Worker مصدر PHP.
  • [ ] عُزلت Headers وCookies وBody بين الطلبات.
  • [ ] نجحت الاختبارات من Ingress العام والمسار الداخلي.
  • [ ] فُصلت المحاولات التاريخية عن دليل التنفيذ المؤكد.
  • [ ] حُفظت أدلة النشر مع سجل التغيير.

لأنماط استجابة قريبة، راجع دليل معالجة PHP2Shell، ودليل RCE الحرج في Next.js 16.4.1، ودليل ثغرات Babelfish TDS. وتربط صفحة الخدمات هذه الضوابط بهندسة المنصات والسحابة والمنتجات.

المراجع

  1. إصدار FrankenPHP 1.13.5
  2. GHSA-j99q-3wr8-xj43: تنفيذ ملف مرفوع غير PHP كشيفرة PHP
  3. GHSA-v7hf-4gqv-hf8p: كشف مصدر PHP مع Worker match وخادم الملفات
  4. GHSA-8qcf-v46r-g2mc: تسرب خرج طلب Worker سابق
  5. توثيق وضع Worker في FrankenPHP
  6. توثيق إعداد FrankenPHP
  7. Derrick Coetzee، صورة «Technician with laptop working on server rack at NERSC»، ترخيص CC0 1.0، Wikimedia Commons

إعداد: Noor Yasser

المراجع الرسمية

تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.

إعداد: Noor Yasser

من القرار إلى التنفيذ

تعمل على تحدٍ تقني مشابه؟

أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةهندسة الأنظمة الخلفية وتكاملات APIمشروع من الأعمالمنصة اللوجستيات