دليل عملي

PHP: إصلاح CVE-2026-91767 وCVE-2026-91769 في OpenSSL

الأمان والمراقبة13 دقيقةً للقراءةعدد الخطوات: 14

في 24 سبتمبر 2026 نشر مشروع PHP تنبيهين أمنيين يخصان امتداد OpenSSL: CVE-2026-91769، وهي تحقق متساهل أكثر مما ينبغي من اسم مضيف TLS، وCVE-2026-91767، وهي قراءة خارج حدود الذاكرة المؤقتة أثناء الفحص نفسه. صُنّفتا متوسطتين وتصلحهما الإصدارات PHP 8.2.34 و8.3.35 و8.4.26 و8.5.11. لا تُقارنان بـ PHP2Shell، لكنهما تخصان كل كود PHP يفتح اتصال TLS صادرًا. نبيّن هنا هل مواقعكم معنية، وأي إصدار تثبّتون على Debian وUbuntu وRHEL وAlmaLinux وcPanel وDocker، وماذا تفعلون مع فرع بلا إصلاح.

المحتويات· ما الذي يصلحه هذان التنبيهان1/13
  1. 01ما الذي يصلحه هذان التنبيهان
  2. 02الخلاصة في سبع نقاط
  3. 03ما تتيحه هاتان الثغرتان وما لا تتيحه
  4. 04مصنّفتان متوسطتين: هل الأمر عاجل؟
  5. 05قياس تعرضكم في أربع خطوات
  6. 06أي إصدار تثبّتون بحسب فرعكم
  7. 07تطبيق الإصلاح بحسب بيئتكم
  8. 08إذا كان فرعكم منتهي الدعم (8.1 وما قبله)
  9. 09لا تضبطوا verify_peer_name على false أبدًا
  10. 10إصلاح ثالث في OpenSSL خلال الربع نفسه
  11. 11حل المشكلات بعد التحديث
  12. 12الأخطاء المصادَفة وعلاجها
  13. 13تثبيت التحديث ضمن روتينكم

ما الذي يصلحه هذان التنبيهان

يستهدف التنبيهان ext/openssl، الامتداد المسؤول عن تشفير TLS في تدفقات PHP. لا يتعلق الأمر بزوار موقعكم، بل بالاتصالات التي يفتحها كود PHP لديكم نحو الخارج، مثل file_get_contents('https://…') أو fopen على رابط https أو stream_socket_client على tls://.

في هذه الحالات تتحقق PHP من أن الشهادة التي يقدّمها الخادم البعيد تطابق اسم المضيف المطلوب. هذا هو الخيار verify_peer_name، وهو مفعّل افتراضيًا. تقع الثغرتان معًا في هذا الفحص. يصف تنبيه CVE-2026-91769 (GHSA-vvx9-73fr-5jjx) تحققًا متساهلًا أكثر مما ينبغي، ويصف تنبيه CVE-2026-91767 (GHSA-xr7j-rvgx-xq5p) قراءة خارج حدود الذاكرة المؤقتة عند مقارنة الأسماء ذات حرف البدل. نُشر التنبيهان في اليوم نفسه، 24 سبتمبر 2026، وتصلحهما الإصدارات نفسها.

الخلاصة في سبع نقاط

  • CVE-2026-91769 — خطورة متوسطة، درجة CVSS 3.1 تساوي 4.3. يفحص التحقق من اسم النظير حقول subjectAltName أولًا، ثم يعود إلى الاسم الشائع (Common Name) حتى حين تعرض الشهادة SAN من نوع DNS لا يطابق الاسم المطلوب.
  • CVE-2026-91767 — خطورة متوسطة، درجة CVSS 3.1 تساوي 6.5 (CWE-122). في الدالة php_openssl_matches_wildcard_name() يؤدي نقص في الطول يُمرَّر إلى memchr() إلى قراءة خارج حدود الذاكرة المؤقتة حين يحتوي اسم حرف البدل في الشهادة على أحرف حرفية أكثر من المضيف الذي يجري التحقق منه.
  • الإصدارات المصحَّحة — PHP 8.2.34 و8.3.35 و8.4.26 و8.5.11 للثغرتين معًا. يظهر الإصداران 8.4.26 و8.5.11 في سجل تغييرات PHP بتاريخ 24 سبتمبر 2026.
  • من المعني — العملاء الذين يعتمدون على القيمة الافتراضية للخيار verify_peer_name عبر file_get_contents() وfopen() وstream_socket_client() على https:// وtls://.
  • الحل المؤقت — لا يذكر التنبيه أي حل. تعطيل التحقق ليس حلًا، بل ثغرة إضافية.
  • الفروع 8.1 وما قبلها — منتهية الدعم ولا يوجد إصلاح من المشروع. قد توجد إصلاحات من التوزيعة أو backports من أطراف ثالثة: تحققوا حزمة بحزمة.
  • الاستغلال — لم نجد في المصادر التي رجعنا إليها أي استغلال مرصود لهاتين الثغرتين.

ما تتيحه هاتان الثغرتان وما لا تتيحه

تتيح CVE-2026-91769 انتحال مضيف. يمكن لشهادة يعتمدها عميلكم لمضيف ما أن تُستعمل للتظاهر بمضيف آخر إذا كان اسمها الشائع (CN) يتضمن الاسم المستهدف. تنص RFC 6125 على تجاهل CN عند وجود SAN من نوع DNS، ولم تكن PHP تفعل ذلك. يرى التنبيه أن الحالة تهم خصوصًا البنية المفتاحية الخاصة (PKI)، أي سلطة داخلية تصدر شهادات لخدمات كثيرة.

تتيح CVE-2026-91767 إسقاط عميل PHP. يستطيع خادم خبيث، أو خادم بسلطة موثوقة، إحداث القراءة خارج الحدود أثناء التحقق، وهذا حجب للخدمة. يوضح التنبيه أن النتيجة لا تؤثر إلا في قرار القبول أو الرفض ولا تُرجع أي محتوى من الكومة. تحفظ صريح: يُقدّر متجه CVSS السرية بدرجة عالية والإتاحة بلا تأثير، وهذا لا ينسجم مع نص الأثر. نشير إلى ذلك دون أن نحسمه.

ما لا تتيحانه. لا يصف التنبيه أي تنفيذ للكود. ولا تُفعَّل أي منهما بطلب من زائر يصل إلى موقعكم. المتجهان كلاهما من نوع الشبكة المجاورة (AV:A): يجب أن يكون المهاجم قريبًا من الاتصال، لا في أي مكان على الإنترنت.

مصنّفتان متوسطتين: هل الأمر عاجل؟

جواب صريح: لا شيء في المصادر التي رجعنا إليها يدل على أن هاتين الثغرتين تُستغلان. ولا نؤكد أكثر من ذلك. لا تُقارنان بـ PHP2Shell (CVE-2026-109618 وCVE-2026-109619) التي تستهدف المفسِّر نفسه وتُفعَّل بطلب HTTP مجهول. نعالج تلك الثغرة على حدة في مقالنا عن PHP2Shell؛ وآخر إصدار من فرعكم، وهو ما يطلب منكم ذلك المقال تثبيته، يتضمن هذه الإصلاحات أيضًا.

فالاستعجال متدرج. إنه حقيقي إذا كان الكود لديكم يستدعي عناوين خارجية عبر تدفقات PHP (واجهات الدفع، وwebhooks الصادرة، واستيراد الخلاصات، والتحقق من التراخيص) أو خدمات داخلية تأتي شهاداتها من PKI خاصة. وهو أقل بكثير لموقع تعريفي لا يجري أي استدعاء صادر. وفي الحالتين يبقى الإصلاح ضمن الفرع نفسه: أدرجوه في أقرب نافذة صيانة بدل تأجيله دون تاريخ.

قياس تعرضكم في أربع خطوات

  1. اقرؤوا إصدار PHP الذي يُقدَّم فعليًا

    على الخادم، نفّذوا php -r 'echo PHP_VERSION, PHP_EOL;'. لا تعتمدوا على OPENSSL_VERSION_TEXT: فالمُصحَّح ليس مكتبة OpenSSL الخاصة بالنظام بل كود الامتداد، أي إصدار PHP. انتبهوا، فقد يختلف سطر الأوامر عما تقدمه مواقعكم: على خادم يستضيف عدة فروع، اقرؤوا أيضًا إصدار كل مجمّع PHP-FPM (خطوة التحقق أدناه). في cPanel يُقرأ الإصدار لكل نطاق، انظروا دليلنا عن محدد إصدار PHP.

  2. ابحثوا عن الاستدعاءات التي تمر عبر تدفقات PHP

    اعرضوا الاستدعاءات الصادرة التي تحمل رابطًا مكتوبًا في الكود: grep -rnE "(file_get_contents|fopen)\(\s*['\"]https?://|stream_socket_client\(\s*['\"]tls://" /var/www --include='*.php'. في استضافة cPanel استبدلوا /var/www بـ /home. أكملوا بالاستدعاءات التي يأتي رابطها من متغير: grep -rnE "(file_get_contents|fopen|stream_socket_client)\(\s*\$" /var/www --include='*.php'. فكّروا في إضافات WordPress ومجلد vendor: كثيرًا ما تختبئ الاستدعاءات الصادرة هناك.

  3. حدّدوا حالات التحقق المعطَّل أصلًا

    نفّذوا grep -rn "verify_peer_name" /var/www --include='*.php'. القيمة false تعني أنه لا يُتحقق من أي اسم مضيف: هذا الكود معرّض لأكثر بكثير من هذين التنبيهين، أيًّا كان إصدار PHP. أصلحوه قبل كل شيء.

  4. صنّفوا مواقعكم

    يكون الموقع أولوية إذا اجتمع فيه فرع دون الحد الأدنى في الجدول التالي واستدعاءات صادرة عبر التدفقات. لا يذكر التنبيه الاستدعاءات المنفذة عبر امتداد cURL، فهو يعدّد تدفقات PHP. يستعمل WordPress ومعظم مكتبات HTTP عادةً cURL عند توفره، لكنها تعود إلى التدفقات في غيابه: لا تستبعدوها دون تحقق.

أي إصدار تثبّتون بحسب فرعكم

مرّر الجدول أفقيًا

فرع PHPالحد الأدنى المصحَّحالحالة
8.58.5.11مصحَّح. ثبّتوا آخر إصدار متاح من 8.5.
8.48.4.26مصحَّح. ثبّتوا آخر إصدار متاح من 8.4.
8.38.3.35مصحَّح. ثبّتوا آخر إصدار متاح من 8.3.
8.28.2.34مصحَّح. خطّطوا للخروج من هذا الفرع، انظروا قائمة التحقق المرتبطة في آخر المقال.
8.1 وما قبله (من 5.6 إلى 8.1)لا يوجد إصدار من المشروعمنتهي الدعم. إصلاح من التوزيعة أو backport من طرف ثالث يجب التحقق منه، وإلا فالترحيل.

تطبيق الإصلاح بحسب بيئتكم

  1. Debian وUbuntu

    حدّثوا الفهرس بـ sudo apt update، ثم حزم فرعكم بـ sudo apt install --only-upgrade 'php8.3*' (استبدلوا 8.3 بفرعكم). لمعرفة المعلّق: apt list --upgradable 2>/dev/null | grep -i php. كثيرًا ما تصلح التوزيعات عبر backport دون تغيير رقم المشروع: اقرؤوا سجل الحزمة بـ apt changelog php8.3-cli | grep -i CVE-2026-91769. مع مستودع طرف ثالث مثل Sury تنطبق الأوامر نفسها.

  2. RHEL وAlmaLinux وRocky Linux

    نفّذوا sudo dnf update 'php*'. إذا كنتم تستعملون تدفق وحدات فالفرع يتبع الوحدة المفعّلة: يعرضها dnf module list --enabled php. ثم تحققوا من السجل بـ rpm -q --changelog php-cli | grep -i CVE-2026-91769. مع مستودع طرف ثالث تتغير أسماء الحزم: كيّفوا النمط مع ما يعيده rpm -qa 'php*'.

  3. cPanel: EasyApache 4 ومحدد PHP

    فروع EasyApache 4 حزم باسم ea-php83 وea-php84 وهكذا. إذا كان لديكم صلاحية root فاعرضوها بـ rpm -qa 'ea-php*' | sort ثم حدّثوها بـ sudo dnf update 'ea-php*'. اقرؤوا السجل بـ rpm -qa --changelog 'ea-php83*' | grep -i CVE-2026-91769 والإصدار الفعلي بـ /opt/cpanel/ea-php83/root/usr/bin/php -v. في الاستضافة المشتركة يتولى المضيف التحديث: دوركم أن تتحققوا، في محدد PHP بـ cPanel (MultiPHP Manager أو Select PHP Version على CloudLinux)، من أن كل نطاق يعمل على فرع مصحَّح.

  4. Docker

    لا تُصلَح الصورة في مكانها: أعيدوا بناءها مع سحب القاعدة المحدَّثة بـ docker build --pull --no-cache -t your-image .، أو docker compose build --pull --no-cache مع Compose، ثم أعيدوا التشغيل بـ docker compose up -d. تحققوا من النتيجة داخل الحاوية بـ docker run --rm your-image php -v. لا تتقدم وسمة عائمة مثل php:8.4-fpm إلا إذا أُعيد بناء الصورة الأصلية: الرقم المعروض هو المرجع لا اسم الوسم.

  5. أعيدوا تشغيل خدمات PHP

    يحتفظ PHP-FPM وApache بالكود القديم في الذاكرة ما لم يُعاد تحميلهما. على Debian أو Ubuntu: sudo systemctl restart php8.3-fpm (كيّفوا الفرع)، وsudo systemctl restart apache2 إذا كنتم تستعملون mod_php. على RHEL أو AlmaLinux: sudo systemctl restart httpd. على cPanel مع PHP-FPM يعطي systemctl list-units 'ea-php*' الاسم الدقيق للخدمة المطلوب إعادة تشغيلها.

  6. تحققوا من الإصدار الذي يُقدَّم فعليًا

    سطر الأوامر ليس خدمة الويب. استعلموا من ملف FPM التنفيذي: php-fpm8.3 -v على Debian وUbuntu، وphp-fpm -v على RHEL ومشتقاته، أو إصدار النطاق في cPanel. يجب أن يبلغ الرقم الحد الأدنى لفرعكم، أو أن يذكر سجله CVE-2026-91769. اختموا باستدعاء صادر تجريبي: php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;'.

إذا كان فرعكم منتهي الدعم (8.1 وما قبله)

بحسب HeroDevs، فإن فروع PHP من 5.6 إلى 8.1 منتهية الدعم ولا تتلقى إصلاحًا من المشروع لهاتين الثغرتين. لا تفترضوا شيئًا في أي اتجاه. ربما نقلت توزيعتكم الإصلاح إلى حزمتها: هذا ممكن وغير مضمون، ويُتحقق منه حزمة بحزمة عبر سجل التغييرات (apt changelog وrpm -q --changelog) وتتبّع الأمان الخاص بالتوزيعة. كما يقدّم ناشرون من أطراف ثالثة backports للإصدارات المهجورة.

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

لا تضبطوا verify_peer_name على false أبدًا

أمام خطأ في الشهادة يغري الأمر بإضافة verify_peer_name => false في stream_context_create. هذا أسوأ من الثغرة: لم يعد يُتحقق من أي اسم مضيف، فتصلح أي شهادة معتمدة لأي مضيف. لا يذكر التنبيه أي حل مؤقت، وهذا الخيار ليس واحدًا منها. حين يفشل اتصال بعد التحديث، أصلحوا الشهادة.

إصلاح ثالث في OpenSSL خلال الربع نفسه

CVE-2026-14355 ثغرة مستقلة: تلف في الذاكرة داخل openssl_encrypt() مع الخوارزمية AES-WRAP-PAD (GH-22187). بحسب سجل تغييرات PHP (https://www.php.net/ChangeLog-8.php) فقد صُحّحت في PHP 8.4.23 بتاريخ 3 يوليو 2026 وفي PHP 8.5.8 بتاريخ 2 يوليو 2026. تمس التشفير لا التحقق من TLS: فلا تغيّر شيئًا في اختبار التعرض أعلاه.

إذا ثبّتم 8.4.26 أو 8.5.11 أو ما بعدهما فلديكم هذا الإصلاح أصلًا. أما الفرعان 8.2 و8.3 فلا نذكر لهما إصدارًا لأننا لم نتحقق منه: اقرؤوا سجل حزمتكم لمعرفة هل ترد فيه CVE-2026-14355.

حل المشكلات بعد التحديث

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

الأخطاء المصادَفة وعلاجها

  • SSL operation failed with code 1 ثم certificate verify failed — الرسالة الكاملة المعتادة: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed. السبب المرجّح: الشهادة تعرض SAN من نوع DNS لا يتضمن المضيف المطلوب، بينما يتضمنه CN. كان الفحص القديم يقبلها بالعودة إلى CN، والجديد يرفضها. اقرؤوا الشهادة بـ openssl s_client -connect interne.your-domain.com:443 -servername interne.your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName. العلاج: إعادة إصدار الشهادة بـ SAN من نوع DNS صحيح لكل اسم مستعمل، وليس تعطيل التحقق أبدًا.
  • file_get_contents(): Failed to enable crypto — تحذير يرافق الخطأ السابق. اقرؤوا الرسالة الكاملة التي تليه: بحسب الإصدار قد تجدون أيضًا Peer certificate CN=… did not match expected CN=…. السبب نفسه والعلاج نفسه.
  • شهادة بلا أي SAN، بـ CN فقط، تفشل مع ذلك — يُبقي الإصلاح العودة إلى CN للشهادات التي لا تحمل معرّف خدمة. فالسبب إذن في مكان آخر: سلطة لا يعتمدها العميل، أو مضيف مستدعى بكنية أو بعنوان IP غير موجود في الشهادة، أو شهادة منتهية الصلاحية. العلاج: إضافة السلطة الداخلية إلى cafile في سياق التدفق، وإعادة إصدار الشهادة بـ SAN.
  • child exited on signal 11 (SIGSEGV) في سجل PHP-FPM — انهيار عامل أثناء استدعاء صادر عبر TLS يتوافق مع CVE-2026-91767. لا تستنتجوا من هذه القرينة وحدها: تحققوا من الإصدار وحدّثوا وانظروا هل يختفي النمط.
  • php -v ما زال يعرض الإصدار القديم — خدمة لم تُعد تشغيلها، أو سطر أوامر وFPM على فرعين مختلفين، أو صورة Docker أُعيد بناؤها دون --pull، أو إصدار النطاق لم يتغير في cPanel. ارجعوا إلى خطوة التحقق.
  • سجل التوزيعة لا يذكر الثغرة — غيابها لا يثبت أن الإصلاح موجود ولا أنه مفقود. راجعوا تتبّع الأمان الخاص بالتوزيعة، وإلا فقارنوا رقم المشروع بالحد الأدنى في الجدول.

تثبيت التحديث ضمن روتينكم

  1. دوّنوا الحد الأدنى في جردكم

    أضيفوا إلى جرد أسطولكم عمودًا باسم "الإصدار الأدنى" لكل فرع، بقيم الجدول. فيصبح أي إصدار دون الحد الأدنى ظاهرًا دون بحث.

  2. خطّطوا لتحديثات PHP

    الإصلاح الأمني في PHP تحديث ثانوي ضمن الفرع نفسه: خصّصوا نافذة منتظمة بدل ورشة عند كل تنبيه، مع إعادة تشغيل الخدمات والتحقق من الإصدار المُقدَّم.

  3. اختبروا استدعاءً صادرًا بعد كل تحديث

    أعيدوا php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;' من كل خادم، واستدعاءً إلى خدماتكم الداخلية. يظهر خطأ الشهادة حينها فورًا، لا عند عميل.

  4. اربطوا هذا الإصلاح ببقية مراقبتكم

    لطريقة جرد الأسطول اقرؤوا جرد إصدارات PHP لأسطول العملاء. وللثغرة الأخطر في الوقت الحالي انظروا PHP2Shell. ولتغيير إصدار موقع اتبعوا دليل محدد PHP في cPanel. ولفرع يوشك أن ينتهي عودوا إلى قائمة التحقق لترحيل PHP 8.2.

اختاروا إصدار PHP لكل موقع

في استضافة ويب ServOrbit.com تختارون إصدار PHP لكل نطاق من cPanel، وتنتقلون إلى فرع ما زال مصحَّحًا بعد اختبار موقعكم.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة