برای رفع آسیبپذیریهای PHP2Shell با شناسههای CVE-2026-109618 و CVE-2026-109619، باید نسخه اصلاحشده PHP را نصب کنیم. اگر بهروزرسانی همه سرورها زمان میبرد، میتوانیم تا پایان آن از محدودیتهای موقت این راهنما استفاده کنیم.
در سایتهایی که به multipart/form-data نیاز ندارند، این درخواستها را با یک قانون فایروال CDN مسدود میکنیم. برای سایتهای نیازمند آپلود یا فرمهای multipart، تنظیمات موقت PHP را در بخش ۴ بررسی میکنیم. قانون فایروال اختیاری است و بهصورت پیشفرض فعال نیست.
این اقدامات جایگزین بهروزرسانی PHP نیستند
طبق اطلاعیه رسمی PHP، تنها نصب اصلاحیه این دو آسیبپذیری را برطرف میکند. قانون فایروال همه درخواستهای multipart، از جمله درخواستهای سالم، را مسدود میکند و حمله را از درخواست عادی تشخیص نمیدهد. تنظیمات موقت PHP هم فقط بعضی روشهای حمله را محدود میکنند. با فعالسازی این محدودیتها، نصب اصلاحیه را به تعویق نمیاندازیم.
پیشنیازها
- دسترسی به تنظیمات PHP و امکان نصب اصلاحیه روی سرور، یا درخواست نصب آن از سرویسدهنده میزبانی.
- برای تنظیم فایروال: فعال بودن پروکسی CDN دامنه و دسترسی به فایروال وبسایت در پنل.
- شناخت فرمها و APIهایی که از multipart استفاده میکنند، مانند آپلود فایل یا ارسال تیکت.
- یک مسیر آزمایشی که ارسال درخواست به آن باعث ثبت سفارش، پرداخت یا تغییر اطلاعات نشود.
- دسترسی به لاگ درخواستهای CDN و آپاستریم برای بررسی نتیجه.
۱. نصب اصلاحیه PHP روی همه سرورها
ابتدا نسخه PHP وبسایت را مشخص میکنیم. ممکن است PHP-FPM یا کانتینر سایت از نسخهای متفاوت با PHP خط فرمان استفاده کند، پس تنها به خروجی php -v اتکا نمیکنیم.
| نسخه PHP | اولین نسخه دارای اصلاحیه |
|---|---|
| 8.2 | 8.2.35 |
| 8.3 | 8.3.36 |
| 8.4 | 8.4.27 |
| 8.5 | 8.5.12 |
نسخههای جدول در اطلاعیه رسمی PHP معرفی شدهاند. اگر PHP را از مخازن توزیع لینوکس نصب کردهایم، اطلاعیه امنیتی و فهرست تغییرات بسته را هم بررسی میکنیم. بعضی توزیعها اصلاحیه را روی نسخه قدیمیتر اعمال میکنند. در این حالت، شماره نسخه بهتنهایی کافی نیست و باید در اطلاعیه بسته، رفع هر دو CVE تایید شده باشد.
اگر از نسخههای قدیمیتر PHP استفاده میکنیم، بسته اصلاحشده را از سرویسدهنده میزبانی یا توزیع لینوکس دریافت میکنیم، یا به نسخهای که همچنان پشتیبانی میشود ارتقا میدهیم.
برای هر وبسایت یا سرور، نسخه فعلی PHP، بسته یا ایمیج جدید و زمان نصب و راهاندازی مجدد را ثبت میکنیم تا موردی از قلم نیفتد. پس از نصب، همه پردازشها و کانتینرهای مربوط را با نسخه اصلاحشده راهاندازی مجدد میکنیم. در پایان، نسخه PHP در حال اجرا و عملکرد سایت را بررسی میکنیم.
۲. انتخاب محدودیت موقت متناسب با سایت
| وضعیت برنامه | اقدام موقت |
|---|---|
| هیچ فرم یا API سایت از multipart استفاده نمیکند | قانون بخش ۳ را فعال و آزمایش میکنیم. |
| آپلود فایل یا فرمهای سایت به multipart نیاز دارند | درخواستهای multipart را مسدود نمیکنیم و تنظیمات موقت PHP در بخش ۴ را بررسی میکنیم. |
| نصب فوری اصلاحیه و استفاده از اقدامات موقت ممکن نیست | دسترسی به برنامه آسیبپذیر را تا نصب اصلاحیه محدود میکنیم. |
بعضی فرمها حتی بدون ارسال فایل از multipart استفاده میکنند. بنابراین نبودن دکمه آپلود برای انتخاب این محدودیت کافی نیست.
۳. مسدود کردن موقت multipart در فایروال CDN
احتمال اختلال در فرمها و آپلود فایل
این قانون تمام درخواستهای multipart را مسدود میکند و ممکن است ثبتنام، ارسال تیکت، آپلود فایل یا بعضی APIها را از کار بیندازد. پیش از فعالسازی، وابستگی این بخشها به multipart را بررسی میکنیم. اگر چند وبسایت داریم، هرکدام را جداگانه آزمایش میکنیم.
-
در پنل، از سرویس توزیع محتوا → وبسایتها، وبسایت مورد نظر را انتخاب میکنیم و وارد فایروال میشویم.
-
اگر فایروال غیرفعال است، آن را فعال میکنیم. سپس افزودن قانون فایروال را انتخاب میکنیم.
-
نام قانون را
temporary-block-multipartمیگذاریم و عملیات Block با کد وضعیت403را انتخاب میکنیم. -
یک گروه شرط میسازیم و فقط شرط زیر را در آن قرار میدهیم:
فیلد مقدار پارامتر هدر نام هدر content-typeعملگر Glob match غیرحساس به حروف ( i_matches)مقدار multipart/form-dataمقدار را دقیقا به همین صورت و بدون افزودن
*وارد میکنیم. عملگرi_matchesدر پیادهسازی فعلی، عبارت را بدون حساسیت به بزرگی و کوچکی حروف در مقدار هدر جستوجو میکند و نیازی به تطبیق کل مقدار ندارد. بنابراینmultipart/form-data; boundary=...و مقادیر دارای پارامترهای دیگر هم با این قانون مسدود میشوند.اگر درخواست چند هدر
Content-Typeداشته باشد، مقدار هرکدام جداگانه بررسی میشود. وجودmultipart/form-dataدر هرکدام برای مسدود شدن درخواست کافی است، حتی اگر مقدار هدر دیگرapplication/jsonباشد. ترتیب این هدرها در نتیجه تاثیری ندارد. -
قانون را ذخیره میکنیم و ترتیب اجرا و شرطهای قوانین دیگر را بررسی میکنیم. اگر درخواست ابتدا با قانونی مانند Allow، Bypass یا چالش تطبیق پیدا کند، قانون جدید برای آن اجرا نمیشود. در صورت تداخل، ترتیب اجرا یا شرطهای قوانین را اصلاح میکنیم و آزمایشهای بخش بعد را انجام میدهیم. تنها جابهجایی قانون در فهرست، تضمین نمیکند که درخواست به آن برسد.
-
قانون را به آدرسهای دارای پسوند
.phpمحدود نمیکنیم، چون مسیرهایی مانند/loginهم ممکن است با PHP اجرا شوند. مسیر آپلود را نیز از قانون مستثنا نمیکنیم، چون درخواستهای multipart همچنان از آن مسیر به برنامه میرسند. اگر سایت به آپلود نیاز دارد، بخش ۴ را دنبال میکنیم. -
دسترسی مستقیم به آپاستریم را طبق راهنمای Whitelist لبههای CDN محدود میکنیم تا نتوان با اتصال مستقیم، قانون CDN را دور زد.
برای آشنایی با گزینههای پنل، آموزش ساخت قانون فایروال و مرجع فایروال را مطالعه میکنیم.
بررسی نتیجه
در دستورهای زیر، example.com و cdn-security-probe را با دامنه و مسیر آزمایشی خود جایگزین میکنیم. از مسیری استفاده میکنیم که درخواست آزمایشی در آن اطلاعاتی را تغییر ندهد یا عملیاتی مانند سفارش و پرداخت انجام ندهد.
ابتدا یک درخواست multipart بدون فایل ارسال میکنیم:
curl -i -F 'cdn_probe=1' https://example.com/cdn-security-probeسپس مقدار هدر را با ترکیبی از حروف بزرگ و کوچک میفرستیم. این درخواست هم باید مسدود شود. دستور زیر را در Bash اجرا میکنیم:
curl -i https://example.com/cdn-security-probe \
-H 'Content-Type: MuLtIpArT/FoRm-DaTa; boundary=cdnprobe' \
--data-binary $'--cdnprobe--\r\n'برای آزمایش هدر تکراری، دو مقدار متفاوت برای Content-Type میفرستیم. دستور زیر هم برای Bash است:
curl --http1.1 -i https://example.com/cdn-security-probe \
-H 'Content-Type: application/json' \
-H 'Content-Type: multipart/form-data; boundary=cdnprobe' \
--data-binary $'--cdnprobe--\r\n'همین درخواست را با جابهجا کردن دو هدر Content-Type نیز تکرار میکنیم. همه این درخواستها باید پاسخ 403 دریافت کنند. در لاگ درخواستهای CDN، مقدار fw_rule_name باید temporary-block-multipart و مقدار fw_blocked باید BLOCKED باشد. این درخواستها نباید در لاگ آپاستریم ثبت شده باشند.
فقط دریافت 403، اجرای قانون جدید را ثابت نمیکند. ممکن است برنامه یا قانون دیگری این پاسخ را داده باشد، به همین دلیل نام قانون را هم در لاگ بررسی میکنیم.
ورود به سایت، فرمها و APIهای JSON را هم آزمایش میکنیم. برای مقایسه، درخواست زیر را با قالب application/x-www-form-urlencoded میفرستیم. قانون جدید نباید آن را مسدود کند و پاسخ برنامه باید مانند قبل باشد:
curl -i --data 'cdn_probe=1' https://example.com/cdn-security-probeاگر درخواست multipart به آپاستریم رسید، فعال بودن فایروال، قانون و پروکسی CDN را بررسی میکنیم. سپس شرط هدر و قوانین دارای اولویت بالاتر را بازبینی میکنیم و پس از اعمال تنظیمات، آزمایش را تکرار میکنیم. تا زمانی که نتیجه مورد انتظار را نگرفتهایم، نباید به این قانون برای مسدود کردن multipart اتکا کنیم.
درخواستهایی که بیش از ۱۰۰ هدر دارند، ممکن است هنگام بررسی شرط هدر با پاسخ 400 رد شوند.
موفقیت این آزمایشها فقط به معنی اجرای درست قانون است، نه رفع آسیبپذیری PHP. تعداد درخواستهای مسدودشده هم تعداد حملهها نیست، چون درخواستهای سالم کاربران نیز ممکن است مسدود شوند.
۴. کاهش موقت ریسک در سایتهای نیازمند آپلود
اگر سایت به multipart نیاز دارد و هنوز نتوانستهایم اصلاحیه را نصب کنیم، اقدامات موقت راهنمای رسمی CVE-2026-109619 را بررسی میکنیم. تنظیم زیر را در فایل php.ini مربوط به PHP وبسایت، یا یکی از فایلهای .ini که هنگام راهاندازی آن بارگذاری میشوند، قرار میدهیم:
session.upload_progress.enabled = 0این تنظیم، ثبت پیشرفت آپلود در session را غیرفعال میکند و خود آپلود فایل را مسدود نمیکند. اگر نمایش درصد پیشرفت آپلود در سایت به این قابلیت وابسته است، آن بخش را پس از تغییر آزمایش میکنیم.
در PHP 8.5، تنظیم زیر را هم طبق همان اطلاعیه امنیتی اعمال میکنیم:
fatal_error_backtraces = 0تنظیم fatal_error_backtraces را در همان فایل .ini قرار میدهیم. این گزینه از PHP 8.5 اضافه شده و تولید backtrace برای خطاهای fatal را کنترل میکند. خاموش کردن آن فقط روش حمله شناختهشده مربوط به همین قابلیت را محدود میکند.
دستورهای بالا برای فایلهای .ini هستند؛ آنها را به همین شکل در فایل pool مربوط به PHP-FPM یا تنظیمات وبسرور قرار نمیدهیم. برای نمونه، گزینه اول در فایل pool به صورت php_admin_flag[session.upload_progress.enabled] = off نوشته میشود. برای جزئیات، مرجع تنظیمات PHP-FPM را مطالعه میکنیم.
پس از ذخیره تنظیمات، همه پردازشهای PHP سایت را راهاندازی مجدد میکنیم و مقادیر فعال در PHP وبسایت را بررسی میکنیم. فایل تنظیمات PHP خط فرمان ممکن است با فایل تنظیمات وبسایت متفاوت باشد. برای تشخیص فایل درست، راهنمای بارگذاری تنظیمات PHP را مطالعه میکنیم.
تغییر این مقادیر با ini_set() در کد برنامه یا فایل .user.ini در PHP-FPM برای این کار کافی نیست، چون باید پیش از پردازش درخواست اعمال شوند. برای بررسی تنظیمات، صفحه phpinfo() را در دسترس عموم قرار نمیدهیم، چون اطلاعات محیط سرور را نمایش میدهد.
این دو تنظیم جای نصب اصلاحیه را نمیگیرند و همه روشهای حمله را پوشش نمیدهند. برای آسیبپذیری CVE-2026-109618 باید راهنمای رسمی مربوط به خطای کمبود حافظه (OOM) را جداگانه مطالعه کنیم.
تنظیم memory_limit=-1 محدودیت حافظه PHP را برمیدارد و مصرف بیش از حد حافظه میتواند سرویس را از دسترس خارج کند. به همین دلیل، پیش از اعمال آن ظرفیت سرور و محدودیت حافظه کانتینر را بررسی میکنیم. محدودیت اندازه درخواست، تعداد بخشهای multipart و پیچیدگی ورودی را هم متناسب با نیاز برنامه انتخاب میکنیم. این محدودیتها باید درخواستهای بدون هدر Content-Length را نیز پوشش دهند.
۵. غیرفعال کردن قانون موقت
اگر قانون جدید باعث اختلال در ثبتنام، ارسال تیکت یا آپلود شد، temporary-block-multipart را غیرفعال و همان بخش را دوباره آزمایش میکنیم. کل فایروال را خاموش نمیکنیم و قوانین دیگر را نگه میداریم.
با غیرفعال شدن قانون، درخواستهای multipart دوباره به سایت میرسند. اگر PHP هنوز آسیبپذیر است، تا نصب اصلاحیه از اقدامات موقت بخش ۴ استفاده میکنیم یا دسترسی به برنامه را محدود میکنیم.
پس از نصب نسخه اصلاحشده روی همه سرورهای سایت و راهاندازی مجدد پردازشهای PHP، میتوانیم قانون موقت را غیرفعال کنیم و فرمها و آپلود فایل را دوباره آزمایش کنیم. برای چند وبسایت، قانون هرکدام را پس از تکمیل بهروزرسانی همان وبسایت غیرفعال میکنیم.
منابع تکمیلی برای مدیر سرور
مستندات زیر نحوه تنظیم PHP و وبسرورها را توضیح میدهند. برای انتخاب اقدام مناسب در برابر PHP2Shell، ابتدا اطلاعیههای امنیتی PHP در بخشهای بالا را مطالعه میکنیم و سپس برای پیادهسازی تنظیمات از این منابع کمک میگیریم.
- PHP: مرجع تنظیمات session و کوکیها.
- Nginx: تعریف شرطها با map و برگرداندن پاسخ با return.
- Caddy: شرطهای تطبیق درخواست و دستور respond.
- Apache همراه با ModSecurity: تعریف قانون با SecRule و بررسی بدنه درخواست با SecRequestBodyAccess. این دستورها به ماژول ModSecurity نیاز دارند و جزو تنظیمات داخلی Apache نیستند.
- Traefik: شرطهای مسیریابی و اولویت اجرای قوانین.
- Lighttpd: کنترل دسترسی با mod_access.
آخرین بررسی منابع این راهنما: ۲۲ اکتبر ۲۰۲۶.
