پرش به محتوای اصلی
آسیب‌پذیری‌های سایت

LFI و RFI چیست؟ تفاوت Local File Inclusion و Remote File Inclusion

LFI و RFI دو نوع آسیب‌پذیری File Inclusion هستند که در اثر کنترل ناکافی فایل یا Template مورد استفاده برنامه ایجاد می‌شوند. در LFI یک فایل محلی سرور Include می‌شود، درحالی‌که RFI به وارد کردن Resource از یک محل راه‌دور مربوط است و می‌تواند در شرایط آسیب‌پذیر پیامدهای جدی‌تری ایجاد کند. جلوگیری از Dynamic File Inclusion، استفاده از Allowlist و Mapping ثابت، محدود کردن Permissionها و غیرفعال نگه داشتن Remote Include از مهم‌ترین راهکارهای جلوگیری از LFI و RFI هستند.

تیم امنیت رخنه‌کاو ۳۶ دقیقه مطالعه انتشار:

LFI و RFI دو نوع آسیب‌پذیری File Inclusion یا «شامل‌کردن فایل» در برنامه‌های تحت وب هستند. Local File Inclusion یا LFI زمانی رخ می‌دهد که ورودی کنترل‌شده توسط کاربر باعث شود برنامه یک فایل موجود روی همان سرور را به‌شکل ناامن Include کند؛ Remote File Inclusion یا RFI نیز زمانی مطرح می‌شود که برنامه بتواند فایل یا منبعی از یک مکان راه‌دور را از طریق همان سازوکار Include وارد پردازش خود کند. هر دو ضعف معمولاً از کنترل ناکافی ورودی پیش از استفاده در توابعی مانند include و require ناشی می‌شوند، اما RFI علاوه بر ضعف برنامه به قابلیت‌ها و تنظیمات محیط اجرا نیز وابسته است.

مهم‌ترین روش جلوگیری از LFI و RFI این است که هیچ‌گاه مسیر فایل مورد استفاده در Include مستقیماً از ورودی کاربر ساخته نشود. استفاده از Allowlist، Mapping شناسه‌ها به فایل‌های ثابت، جداسازی فایل‌های قابل Include، محدود کردن Permissionها و غیرفعال نگه داشتن قابلیت‌های غیرضروری Include از راه دور از مهم‌ترین کنترل‌های دفاعی هستند.

File Inclusion چیست؟

بسیاری از وب‌سایت‌ها برای جلوگیری از تکرار کد، بخش‌های مختلف برنامه را در فایل‌های جداگانه نگهداری می‌کنند.

برای مثال یک برنامه PHP ممکن است Header، Footer، Menu، Configuration یا بخش‌های مختلف یک صفحه را در فایل‌های مجزا قرار دهد و در زمان اجرا آنها را وارد صفحه اصلی کند.

از نظر مفهومی ساختار برنامه می‌تواند چنین باشد:

index.php
templates/
    header.php
    footer.php
    profile.php
    dashboard.php

زمانی که کاربر صفحه پروفایل را باز می‌کند، برنامه ممکن است فایل مربوط به Profile را بارگذاری کند.

این معماری به‌خودی‌خود ناامن نیست.

مشکل زمانی ایجاد می‌شود که Application به‌جای آنکه خودش مشخص کند چه فایلی باید Include شود، این تصمیم را مستقیماً یا غیرمستقیم به داده قابل‌کنترل توسط کاربر واگذار کند.

برای مثال یک Anti-Pattern مفهومی می‌تواند چنین باشد:

$page = request_parameter('page');
include($page);

در این طراحی، برنامه در واقع از کاربر می‌پرسد:

«کدام فایل را باید وارد برنامه کنم؟»

اگر هیچ محدودیت مناسبی روی $page وجود نداشته باشد، Trust Boundary از بین می‌رود.

OWASP آسیب‌پذیری File Inclusion را ضعفی مرتبط با Dynamic File Inclusion می‌داند که در آن ورودی کاربر بدون Validation کافی برای تعیین فایل مورد استفاده قرار می‌گیرد. پیامد این ضعف بسته به شرایط می‌تواند از افشای اطلاعات تا اجرای کد، Cross-Site Scripting یا Denial of Service گسترش پیدا کند. LFI چیست؟

LFI چیست؟

LFI مخفف Local File Inclusion است.

در Local File Inclusion، برنامه فایلی را Include می‌کند که در محیط محلی همان سرور یا Application وجود دارد.

OWASP، LFI را فرآیند Include کردن فایل‌هایی تعریف می‌کند که از قبل به‌صورت محلی روی سرور حضور دارند، در شرایطی که مکانیزم Include پویا به ورودی غیرقابل‌اعتماد متکی است.

نکته مهم این است که LFI فقط «خواندن فایل» نیست.

در بسیاری از فناوری‌ها Include معنایی فراتر از File Read دارد.

اگر Runtime یک فایل را به‌عنوان بخشی از برنامه پردازش کند، نوع فایل و نحوه رفتار Interpreter می‌تواند روی نتیجه تأثیر بگذارد.

بنابراین باید میان این دو مفهوم تفاوت قائل شد:

File Read

و:

File Include / Evaluation

ممکن است دو آسیب‌پذیری مختلف بتوانند به یک فایل مشابه دسترسی پیدا کنند، اما اثر آنها یکسان نباشد.

مثال مفهومی LFI

فرض کنید یک سایت دارای سه صفحه ثابت باشد:

home
profile
contact

طراحی مناسب می‌تواند به شکل زیر باشد:

home     → templates/home.php
profile  → templates/profile.php
contact  → templates/contact.php

کاربر فقط کلید منطقی profile را انتخاب می‌کند و Application خودش مسیر فایل را تعیین می‌کند.

در طراحی ناامن ممکن است کاربر مستقیماً نام یا مسیر فایل Includeشده را کنترل کند:

User Input
    ↓
File Path
    ↓
include / require

اگر برنامه نتواند ورودی را فقط به فایل‌های مجاز محدود کند، احتمال LFI ایجاد می‌شود. RFI چیست؟

RFI چیست؟

RFI مخفف Remote File Inclusion است.

در این حالت Application نه یک فایل محلی، بلکه منبعی از خارج سرور را وارد سازوکار Include می‌کند.

OWASP توضیح می‌دهد که Remote File Inclusion زمانی رخ می‌دهد که مکانیزم Include آسیب‌پذیر بتواند یک URL یا محل خارجی را به‌عنوان فایل مورد استفاده قرار دهد.

این تفاوت بسیار مهم است.

در LFI، فایل هدف از قبل در محیط محلی وجود دارد.

در RFI، فایل از منبع خارجی دریافت می‌شود.

به‌صورت مفهومی:

LFI:

Untrusted Input
      ↓
Local File
      ↓
Application Include

در حالی که:

RFI:

Untrusted Input
      ↓
Remote Resource
      ↓
Application Include

به همین دلیل RFI در محیط‌هایی که Include از URL یا منابع Remote امکان‌پذیر است، می‌تواند پیامد بسیار جدی داشته باشد.

MITRE این خانواده ضعف را برای PHP با شناسه CWE-98 یعنی Improper Control of Filename for Include/Require Statement in PHP Program ثبت کرده است. این CWE توضیح می‌دهد که اگر برنامه ورودی خارجی را قبل از استفاده در require، include یا سازوکارهای مشابه به‌درستی محدود نکند، بسته به نسخه و Configuration می‌تواند File Inclusion محلی یا راه‌دور ایجاد شود. تفاوت LFI و RFI چیست؟

تفاوت LFI و RFI چیست؟

تفاوت اصلی در محل فایلی است که Application آن را Include می‌کند.

ویژگیLFIRFI
نام کاملLocal File InclusionRemote File Inclusion
فایل هدففایل محلی سرورفایل یا Resource راه‌دور
محل ResourceFile System یا محیط محلیمنبع خارجی
نیاز احتمالی به Path Traversalدر بسیاری از سناریوها ممکن استالزاماً خیر
وابستگی به تنظیمات Remote Includeمعمولاً نداردمعمولاً دارد
خطر افشای فایل محلیبالا در صورت دسترسی نامناسبهدف اصلی نیست
احتمال اجرای محتوای خارجیهدف مستقیم نیستدر محیط آسیب‌پذیر ممکن است
کنترل اصلیAllowlist و File MappingAllowlist + غیرفعال کردن Remote Include
ریشه مشترکورودی غیرقابل‌اعتماد در File Inclusionورودی غیرقابل‌اعتماد در File Inclusion

یک اشتباه رایج این است که تصور کنیم LFI نسخه «کم‌خطر» RFI است.

این برداشت صحیح نیست.

LFI در شرایط خاص می‌تواند پیامد بسیار جدی داشته باشد و شدت واقعی آن باید براساس Application Runtime، نوع فایل‌های قابل دسترس، Permission برنامه و نحوه پردازش فایل ارزیابی شود. ارتباط LFI با Path Traversal چیست؟

ارتباط LFI با Path Traversal چیست؟

Path Traversal و LFI رابطه نزدیکی دارند، اما یک آسیب‌پذیری واحد نیستند.

Path Traversal یعنی برنامه اجازه دهد یک مسیر از محدوده تعیین‌شده خارج شود.

LFI یعنی برنامه یک فایل محلی ناخواسته را وارد سازوکار Include خود کند.

به‌صورت ساده:

Path Traversal:
مشکل اصلی → کنترل مسیر

LFI:
مشکل اصلی → Include شدن فایل محلی

در بسیاری از LFIها، Path Traversal ابزاری است که باعث می‌شود Application به فایل خارج از Template Directory برسد.

MITRE نیز در CWE-98 اشاره می‌کند که اصطلاح Local File Inclusion اغلب در شرایطی دیده می‌شود که Remote Download غیرفعال است یا بخشی از Filename ثابت است و ضعف همراه با Relative Path Traversal امکان دسترسی به فایل محلی را فراهم می‌کند.

اما هر Path Traversal الزاماً LFI نیست.

فرض کنید Endpoint دانلود یک فایل را فقط به کاربر ارسال کند:

File path → read → HTTP response

در اینجا ممکن است Path Traversal وجود داشته باشد ولی فایل در Application Include نشده باشد.

در مقابل:

File path → include → Application Runtime

به File Inclusion نزدیک می‌شویم.

ارتباط LFI و Directory Traversal

Directory Traversal نام رایج دیگری برای Path Traversal است.

اگر Application مسیر Template را از User Input بسازد، مهاجم ممکن است بتواند از محدوده Template Directory خارج شود.

اما نکته امنیتی برای توسعه‌دهنده این نیست که «چطور یک Traversal Pattern را فیلتر کنیم».

سؤال درست این است:

«چرا کاربر اساساً اجازه دارد مسیر Template را تعیین کند؟»

طراحی امن باید مسئله را یک مرحله قبل حل کند.

به‌جای:

page → filename

بهتر است:

page ID
   ↓
Server-side mapping
   ↓
Known template

استفاده شود.

LFI چگونه ایجاد می‌شود؟

ریشه اصلی LFI معمولاً Dynamic Inclusion ناامن است.

فرض کنید برنامه دارای چنین جریان داده‌ای باشد:

HTTP Request
     ↓
page parameter
     ↓
ساخت نام فایل
     ↓
include()

اگر هیچ Allowlist قابل‌اعتمادی بین User Input و Include وجود نداشته باشد، برنامه وارد منطقه خطر شده است.

دریافت مستقیم Filename از کاربر

یکی از ساده‌ترین Anti-Patternها دریافت Filename مستقیم است.

برای مثال:

$template = get_parameter('template');
include($template);

مشکل این کد خود include نیست.

مشکل این است که تصمیم امنیتی درباره فایل Includeشده به ورودی غیرقابل‌اعتماد واگذار شده است.

ساخت مسیر به‌وسیله String Concatenation

برخی توسعه‌دهندگان تصور می‌کنند اضافه کردن یک Directory ثابت مشکل را حل می‌کند.

برای مثال به‌صورت مفهومی:

"templates/" + user_input

اما اگر Path نهایی Resolve نشود و Boundary بررسی نگردد، وجود Base Directory به‌تنهایی تضمین امنیت نیست.

استفاده از مقدار ذخیره‌شده در Database

داده‌ای که از Database آمده الزاماً Trusted نیست.

ممکن است User Input در مرحله قبلی در Database ذخیره شده باشد:

User
  ↓
Database
  ↓
Template Loader
  ↓
Include

Stored Input همچنان می‌تواند Untrusted باشد.

پارامترهای Template یا Theme

برنامه‌هایی که به کاربر اجازه انتخاب Layout، Template، Language یا Theme می‌دهند نیز باید بررسی شوند.

اگر نام انتخاب‌شده مستقیماً به Filename تبدیل شود، خطر ایجاد می‌شود.

راه امن‌تر استفاده از Mapping محدود است.

RFI چگونه ایجاد می‌شود؟

RFI معمولاً دو شرط اصلی دارد.

اول، User Input باید روی فایل یا Resource مورد Include اثر بگذارد.

دوم، Environment باید اجازه استفاده از Resource راه‌دور در سازوکار Include را بدهد.

در PHP سنتی، قابلیت‌هایی مانند URL-aware stream wrapperها می‌توانستند در این مسئله نقش داشته باشند.

مستندات رسمی PHP می‌گویند allow_url_include اجازه استفاده از URL-aware fopen wrapperها را برای include، include_once، require و require_once فراهم می‌کند و فعال بودن آن نیازمند فعال بودن allow_url_fopen است. مقدار پیش‌فرض allow_url_include برابر Off یا 0 است و این Directive از PHP 7.4 منسوخ شده است.

این نکته مهم است، زیرا RFI کلاسیک در PHP مدرن معمولاً نسبت به محیط‌های قدیمی محدودتر است.

با این حال یک نتیجه اشتباه نباید گرفته شود:

«چون allow_url_include خاموش است، File Inclusion دیگر مهم نیست.»

این نتیجه غلط است.

غیرفعال بودن Remote Include فقط یکی از مسیرهای RFI را محدود می‌کند.

LFI، Path Traversal، Dynamic Template Loading و سایر مشکلات کنترل Filename همچنان ممکن هستند.

allow_url_fopen و allow_url_include چه تفاوتی دارند؟

این دو Directive در PHP کاربرد یکسانی ندارند.

allow_url_fopen قابلیت استفاده از URL-aware wrapperها را برای بسیاری از File Functionها فعال می‌کند.

allow_url_include مشخصاً استفاده از این Wrapperها را در سازوکارهای:

include
include_once
require
require_once

کنترل می‌کند.

مستندات PHP نشان می‌دهند مقدار پیش‌فرض allow_url_fopen برابر On و مقدار پیش‌فرض allow_url_include برابر Off است. همچنین allow_url_include بدون allow_url_fopen قابل استفاده نیست.

از نظر امنیتی، Application نباید امنیت File Inclusion خود را صرفاً به این تنظیمات واگذار کند.

حتی اگر Remote Include در Environment غیرفعال باشد، کدی مانند:

include(user_controlled_filename)

همچنان طراحی نامناسبی است.

تفاوت include و require از نظر LFI و RFI

در PHP، include و require هر دو برای وارد کردن فایل در برنامه استفاده می‌شوند.

تفاوت اصلی آنها بیشتر در رفتار هنگام Failure است؛ اما از نظر اصل File Inclusion Security، هیچ‌کدام نباید Filename غیرقابل‌اعتماد دریافت کنند.

استفاده از require به‌جای include یک کنترل امنیتی برای جلوگیری از LFI یا RFI نیست.

همین مسئله درباره:

include_once
require_once

نیز صادق است.

عبارت once فقط رفتار بارگذاری تکراری فایل را تغییر می‌دهد و Trust Boundary را اصلاح نمی‌کند.

LFI چه خطراتی دارد؟

شدت LFI به محیط بستگی دارد.

نباید هر LFI را بدون تحلیل معادل Remote Code Execution بدانیم؛ اما نباید آن را یک ضعف ساده نمایش فایل نیز در نظر گرفت.

افشای فایل‌های حساس

یکی از پیامدهای محتمل دسترسی به فایل‌هایی است که Application نباید در اختیار کاربر قرار دهد.

این فایل‌ها ممکن است شامل Configuration، Log، Backup، فایل‌های Application یا اطلاعات داخلی باشند.

اگر Configuration شامل Credential یا Endpointهای داخلی باشد، حادثه می‌تواند دامنه بیشتری پیدا کند.

افشای Source Code

در برخی شرایط محتوای فایل‌های برنامه ممکن است در دسترس قرار گیرد.

Source Code می‌تواند اطلاعاتی درباره:

ساختار API، Database Schema، Authentication Logic، مسیرهای مدیریتی و Dependencyها

ارائه کند.

Source Code Disclosure حتی بدون اجرای کد نیز یک Incident امنیتی قابل‌توجه است.

دسترسی به Logها

Logها ممکن است اطلاعات Request، Error، Session Metadata یا سایر جزئیات محیط را داشته باشند.

به همین دلیل Application Process نباید به Logهایی که نیاز ندارد دسترسی داشته باشد.

افشای تنظیمات و Secretها

در معماری ضعیف ممکن است Secretها در File System ذخیره شده باشند و Process وب دسترسی Read به آنها داشته باشد.

LFI در چنین محیطی می‌تواند Confidentiality را تحت تأثیر قرار دهد.

به همین دلیل Secret Management و Least Privilege در کنار اصلاح خود LFI اهمیت دارند.

اجرای ناخواسته محتوا

اگر Runtime فایل Includeشده را به‌عنوان Code تفسیر کند و محتوای آن شرایط لازم برای پردازش اجرایی را داشته باشد، شدت مشکل می‌تواند افزایش یابد.

این پیامد به فناوری، نوع فایل و Context بستگی دارد و نباید برای همه LFIها به‌صورت خودکار ادعا شود.

MITRE برای CWE-98 اجرای کد غیرمجاز را یکی از پیامدهای ممکن File Inclusion می‌داند، اما تحقق آن به شرایط برنامه و Environment وابسته است.

RFI چه خطراتی دارد؟

RFI به‌دلیل ورود Resource از یک منبع خارجی می‌تواند در محیط‌های آسیب‌پذیر بسیار خطرناک باشد.

OWASP پیامدهای File Inclusion را شامل Code Execution، Information Disclosure و Denial of Service می‌داند.

کنترل محتوای Includeشده

تفاوت مهم RFI با LFI این است که در RFI فایل از Location راه‌دور دریافت می‌شود.

اگر منبع فایل نیز تحت کنترل مهاجم قرار گیرد، Application دیگر فقط به داده موجود روی Server وابسته نیست.

این موضوع دلیل حساسیت تاریخی RFI است.

اجرای Code در سمت Server

در Configurationهای آسیب‌پذیر، فایل دریافت‌شده ممکن است در Context برنامه تفسیر شود.

MITRE این پیامد را به‌عنوان Execute Unauthorized Code or Commands برای CWE-98 مطرح می‌کند.

Information Disclosure

حتی در شرایطی که Remote Code Execution حاصل نشود، File Inclusion می‌تواند اطلاعات Application را افشا کند یا رفتار برنامه را تغییر دهد.

Denial of Service

وابستگی به Resource خارجی یا پردازش محتوای غیرمنتظره می‌تواند Availability را نیز تحت تأثیر قرار دهد.

آیا RFI هنوز در PHP جدید مهم است؟

بله، ولی باید با Context صحیح بررسی شود.

allow_url_include در PHP به‌صورت پیش‌فرض خاموش است و از نسخه 7.4 Deprecated شده است.

این موضوع باعث شده سناریوهای کلاسیک RFI که در PHPهای قدیمی بسیار رایج بودند در Environmentهای مدرن کمتر قابل تحقق باشند.

اما این موضوع سه دلیل برای نادیده گرفتن RFI ایجاد نمی‌کند.

اول اینکه Legacy Applicationها هنوز وجود دارند.

دوم اینکه Configurationهای سفارشی می‌توانند متفاوت باشند.

سوم اینکه مفهوم Remote Resource Inclusion فقط به یک Directive خاص محدود نیست و طراحی ناامن Resource Loading در فناوری‌های مختلف می‌تواند اشکال دیگری داشته باشد.

بنابراین Code باید مستقل از Configuration امن باشد.

به‌عبارت دیگر:

Secure Code + Secure Configuration

لازم است، نه:

Insecure Code + امید به تنظیمات سرور

LFI و RFI در وردپرس

WordPress Core و بسیاری از Pluginها و Themeها از Templateها و فایل‌های PHP استفاده می‌کنند.

وجود include یا Template Loader در وردپرس به معنی آسیب‌پذیری نیست.

خطر زمانی ایجاد می‌شود که Plugin یا Theme اجازه دهد User Input تعیین کند کدام فایل Load شود.

Template Loading در وردپرس

WordPress توابعی مانند get_template_part() برای بارگذاری Template Partها ارائه می‌کند. مستندات رسمی نشان می‌دهند این تابع Templateهای نام‌گذاری‌شده را پیدا کرده و بارگذاری می‌کند.

توسعه‌دهنده نباید بدون Validation مناسب مقدارهای Request را مستقیماً به نام Template تبدیل کند.

روش بهتر این است که Templateهای مجاز از قبل مشخص شوند.

مثلاً:

profile  → profile.php
account  → account.php
orders   → orders.php

کاربر هیچ Filename واقعی ارسال نمی‌کند.

استفاده از validate_file در WordPress

WordPress تابع validate_file() را برای بررسی Filename و Path ارائه می‌کند.

براساس مستندات رسمی، این تابع می‌تواند وجود Directory Traversal، Windows Drive Path و قرار نداشتن فایل در Allowed Files List را تشخیص دهد.

این قابلیت برای Plugin Development مفید است، اما همچنان بهتر است معماری از ابتدا براساس Allowlist و Mapping طراحی شود.

Pluginها و Themeهای سفارشی

بخش‌هایی که باید بیشتر بررسی شوند عبارت‌اند از Template Selector، Import/Export، فایل زبان، Email Template، PDF Generator، Custom Layout، Backup و File Manager.

وجود این قابلیت‌ها به معنی آسیب‌پذیری نیست.

نقطه اصلی این است:

آیا User Input به File Inclusion Sink می‌رسد؟

تفاوت LFI با Path Traversal و File Read

برای جلوگیری از سردرگمی، سه مفهوم را کنار یکدیگر قرار دهیم.

ویژگیPath TraversalArbitrary File ReadLFI
کنترل Pathبلهمعمولاً بلهممکن است
فایل محلیمعمولاًبلهبله
Include شدن در Runtimeالزاماً خیرخیربله
هدف اصلیخروج از Directory مجازخواندن فایلوارد کردن فایل به Application
احتمال اجرای محتواذاتاً نهذاتاً نهبسته به Runtime ممکن است

این تفاوت در گزارش‌های امنیتی مهم است.

اگر Scanner فقط ثابت کند فایل خوانده می‌شود، نباید بدون Evidence آن را LFI منجر به RCE معرفی کرد.

گزارش باید دقیقاً رفتاری را توصیف کند که مشاهده شده است.

تفاوت RFI با SSRF

Remote File Inclusion با Server-Side Request Forgery یا SSRF نیز گاهی اشتباه گرفته می‌شود.

در SSRF، Application از طرف مهاجم Request شبکه‌ای ارسال می‌کند.

در RFI، Resource راه‌دور وارد مکانیزم Include برنامه می‌شود.

ویژگیRFISSRF
رفتار اصلیInclude Resourceارسال Request توسط Server
نیاز به Includeبلهخیر
هدف رایجمحتوای راه‌دور در Runtimeسرویس‌های داخلی یا خارجی
ریسک Code Evaluationممکن استذات SSRF نیست
دفاع اصلیFile Allowlist و حذف Dynamic IncludeURL/Network Allowlist و Egress Control

یک برنامه در شرایط پیچیده می‌تواند بیش از یک نوع ضعف داشته باشد، اما این اصطلاح‌ها نباید به‌جای یکدیگر استفاده شوند.

چگونه LFI و RFI را به‌صورت امن شناسایی کنیم؟

در رخنه‌کاو رویکرد تست باید دفاعی و مبتنی بر مجوز باشد.

هدف اصلی این نیست که به فایل حساس واقعی دسترسی پیدا کنیم؛ هدف آن است که ثابت کنیم Data Flow ناامن وجود دارد.

Code Review

موثرترین روش در بسیاری از Applicationهای PHP بررسی کد است.

MITRE نیز Manual White-Box Analysis را برای CWE-98 روشی بسیار مؤثر می‌داند، زیرا معمولاً تعداد Include و Require Statementها در برنامه محدود و قابل جست‌وجو است.

در Code Review ابتدا Sinkها را پیدا کنید:

include
include_once
require
require_once
Template loaders
Custom file loaders

سپس بررسی کنید داده واردشده به آنها از کجا آمده است.

Sourceهای مهم شامل Request Parameter، Form Data، JSON Body، Cookie، Header، Database Field، فایل Configuration قابل‌ویرایش و APIهای خارجی هستند.

Data Flow Analysis

ساختار امن باید تقریباً چنین باشد:

User Choice
     ↓
Validation / Mapping
     ↓
Known File Identifier
     ↓
Trusted Path
     ↓
Include

ساختار پرخطر:

User Input
     ↓
Filename Construction
     ↓
Include

هر Sink باید تا Source دنبال شود.

SAST

ابزارهای Static Application Security Testing می‌توانند Data Flow میان ورودی خارجی و File Inclusion Function را شناسایی کنند.

MITRE نیز Automated Static Analysis را برای پیدا کردن تأثیر ورودی خارجی روی Filename مفید می‌داند، هرچند Validation سفارشی می‌تواند باعث False Positive شود.

DAST

در Dynamic Testing بهتر است از Environment آزمایشی استفاده شود.

می‌توان یک Template آزمایشی کاملاً بی‌خطر در محدوده‌ای که نباید قابل Include باشد قرار داد و بررسی کرد آیا Application می‌تواند خارج از Mapping مورد انتظار به آن دسترسی پیدا کند.

برای RFI نیز به‌جای استفاده از Payload اجرایی می‌توان صرفاً رفتار Validation را بررسی کرد و تأیید کرد که URL یا Resource خارجی توسط Application رد می‌شود.

اثبات ضعف نیازی به اجرای Command، دسترسی به Secret یا تغییر سیستم ندارد. روش اصلی جلوگیری از LFI و RFI

روش اصلی جلوگیری از LFI و RFI

قانون اصلی بسیار ساده است:

User Input نباید Filename مورد استفاده در Include را تعیین کند.

این مهم‌ترین کنترل است.

به‌جای Dynamic Filename، از Static Mapping استفاده کنید.

برای مثال مدل مفهومی امن:

$allowed_pages = [
    'home'    => 'templates/home.php',
    'profile' => 'templates/profile.php',
    'contact' => 'templates/contact.php',
];

$key = get_parameter('page');

if (isset($allowed_pages[$key])) {
    include $allowed_pages[$key];
}

در این مدل کاربر فقط یک Key محدود را کنترل می‌کند.

Filenameها داخل Code و تحت کنترل توسعه‌دهنده هستند.

این طراحی بسیار بهتر از Sanitization پیچیده روی Path است.

استفاده از Allowlist به‌جای Blocklist

یکی از مهم‌ترین اصول امنیت File Inclusion استفاده از Allowlist است.

فرض کنیم Application سه Template دارد.

امنیت بهتر است چنین تعریف شود:

مجاز:
home
profile
contact

نه:

همه چیز مجاز است به جز Patternهای مشکوک

Blocklist نیاز دارد تمام روش‌های نامعتبر را از قبل پیش‌بینی کنید.

Allowlist فقط Business Requirement واقعی را می‌پذیرد.

اگر Application فقط پنج Language، سه Template یا چهار Report دارد، هیچ دلیل منطقی برای پذیرش String آزاد وجود ندارد.

از شناسه به‌جای Filename استفاده کنید

بهتر است URL سایت ساختار منطقی داشته باشد.

مثلاً:

page=account

نه:

file=[filesystem-path]

Application سپس account را به Template داخلی مرتبط می‌کند.

این اصل همان رویکردی است که در جلوگیری از Path Traversal نیز بسیار مؤثر است.

هرچه User Input از File System دورتر شود، سطح حمله کمتر خواهد شد.

مسیرهای Include را ثابت نگه دارید

Include Directory بهتر است در Code یا Configuration مورد اعتماد تعریف شود.

برای مثال:

APPLICATION_TEMPLATE_ROOT

سپس تنها Filenameهای تأییدشده زیر همان Root استفاده شوند.

مسیر Root نباید از Request قابل تغییر باشد.

Canonicalization در چه شرایطی لازم است؟

اگر به هر دلیل برنامه واقعاً نیاز دارد Path دینامیک داشته باشد، مسیر باید قبل از عملیات امنیتی Normalize یا Canonical شود.

سپس باید بررسی شود Path نهایی داخل Base Directory مجاز باقی مانده است.

اما حتی این روش نیز جای Allowlist را نمی‌گیرد.

Canonicalization ابزار دفاعی مکمل است.

معماری Identifier-based معمولاً ساده‌تر و قابل‌اعتمادتر است.

غیرفعال نگه داشتن Remote Include

در PHP، allow_url_include به‌صورت پیش‌فرض خاموش است و از PHP 7.4 Deprecated شده است. این وضعیت باید حفظ شود مگر نیاز فنی بسیار خاص و کاملاً بررسی‌شده‌ای وجود داشته باشد.

از نظر طراحی مدرن، Application معمولاً نباید برای اجرای منطق خود فایل PHP را از یک URL خارجی Include کند.

اگر برنامه نیاز دارد داده Remote دریافت کند، بهتر است این کار با HTTP Client مشخص انجام شود و پاسخ به‌عنوان Data پردازش شود، نه Code.

تفاوت بسیار مهم است:

Remote Data

نباید به:

Remote Executable Template / Code

تبدیل شود.

allow_url_fopen را براساس نیاز واقعی تنظیم کنید

غیرفعال کردن allow_url_fopen در محیطی که نیازی به URL-aware File Operation ندارد می‌تواند Attack Surface را کاهش دهد.

با این حال بعضی Applicationها ممکن است به Remote File Access نیاز داشته باشند.

بنابراین این تصمیم باید براساس Dependencyها و Architecture گرفته شود.

مهم‌تر از همه، هیچ تنظیم php.ini نباید جای Secure Coding را بگیرد.

فایل‌های Include را خارج از Public Access نگه دارید

MITRE توصیه می‌کند Library، Include و Utility Fileها در صورت امکان خارج از Web Document Root ذخیره شوند یا Direct Access به آنها توسط Web Server محدود شود.

این کنترل چند مزیت دارد.

کاربر نمی‌تواند Include File را مستقیماً از طریق URL درخواست کند.

همچنین Errorهای Routing یا Misconfiguration کمتر باعث افشای فایل می‌شوند.

Least Privilege را جدی بگیرید

اگر PHP-FPM یا Web Server فقط باید به چند Directory مشخص دسترسی داشته باشد، نباید Permission گسترده به کل سیستم داشته باشد.

Least Privilege باعث می‌شود حتی در صورت وجود LFI، Filesystem Exposure محدودتر باشد.

برای مثال Application Process نباید بدون دلیل به Backup سایر Applicationها، SSH Keyها یا فایل‌های Serviceهای دیگر دسترسی Read داشته باشد.

این کنترل LFI را رفع نمی‌کند، اما Blast Radius را کاهش می‌دهد.

Container و LFI

در Containerized Applicationها گاهی تصور می‌شود وجود Container به‌تنهایی مشکل را حل می‌کند.

Container می‌تواند Isolation مفیدی ایجاد کند، اما تنها در صورتی که درست پیکربندی شده باشد.

اگر Container دارای Volumeهای حساس باشد، Secretهای متعدد Mount شده باشند یا Permission گسترده داشته باشد، LFI همچنان می‌تواند اطلاعات باارزشی افشا کند.

بهتر است:

Volumeها حداقلی باشند،

Secretها فقط در سرویس موردنیاز قرار گیرند،

Filesystem تا حد امکان Read-Only باشد،

و Service Account کمترین Permission لازم را داشته باشد.

مدیریت امن Templateها

Template انتخاب‌شده باید از لیست مشخصی بیاید.

مثلاً در یک فروشگاه:

invoice
email-confirmation
password-reset
order-summary

این مقادیر باید به فایل‌های ثابت Mapping شوند.

کاربر یا Admin سطح پایین نباید بتواند Filename Arbitrary وارد کند مگر محصول واقعاً یک Template Platform کنترل‌شده باشد.

مدیریت فایل‌های زبان

Language Loaderها یکی از مکان‌های رایج Dynamic File Loading هستند.

اگر سایت سه زبان دارد، فقط همان سه Code را قبول کنید.

مثلاً:

fa
en
de

هر مقدار خارج از Allowlist باید رد شود.

نیازی نیست Language Parameter تبدیل مستقیم به Filename شود.

نقش Input Validation در LFI و RFI

Input Validation مهم است اما باید براساس Business Rule باشد.

Validation مناسب یعنی:

آیا این ورودی یکی از گزینه‌های مجاز است؟

نه:

آیا این ورودی شبیه حمله به نظر نمی‌رسد؟

این دو دیدگاه کاملاً متفاوت هستند.

روش دوم معمولاً به Blocklist و Pattern Matching وابسته می‌شود.

روش اول Deny by Default است.

آیا حذف Characterهای خاص کافی است؟

خیر.

حذف Character یا Pattern خاص از Path روش دفاعی قابل اتکایی نیست.

Filename و Path ممکن است از Encoding، Normalization، Wrapperها یا تفاوت Platform تأثیر بگیرند.

علاوه بر این، برنامه ممکن است در مراحل مختلف ورودی را Decode کند.

هدف Secure Coding نباید «پیدا کردن تمام رشته‌های بد» باشد.

هدف باید حذف Dynamic Inclusion غیرضروری باشد.

آیا Extension Check کافی است؟

خیر.

بررسی اینکه Filename با .php یا Extension دیگری تمام می‌شود نمی‌تواند File Inclusion را به‌تنهایی امن کند.

Extension فقط یکی از ویژگی‌های فایل است.

مسیر، Source، Allowlist و Location نهایی نیز باید معتبر باشند.

آیا basename به‌تنهایی کافی است؟

توابعی که فقط بخش Filename را از Path استخراج می‌کنند ممکن است در برخی طراحی‌ها مفید باشند، اما نباید به‌تنهایی سیاست امنیتی Application محسوب شوند.

اگر برنامه دارای چهار Template مشخص است، Allowlist چهار Template بسیار مطمئن‌تر از تلاش برای تبدیل هر User Input به Filename «تمیز» است.

WAF و جلوگیری از LFI و RFI

WAF می‌تواند برخی Patternهای File Inclusion یا Path Traversal را شناسایی کند.

اما WAF مشکل اصلی را حل نمی‌کند.

اگر Application چنین معماری‌ای داشته باشد:

include(user_input)

حتی بهترین WAF نیز فقط یک لایه جانبی است.

WAF ممکن است Encoding، تغییر Syntax یا Vector متفاوت را تشخیص ندهد.

بنابراین ترتیب اولویت باید چنین باشد:

Secure Architecture
      ↓
Secure Coding
      ↓
Least Privilege
      ↓
Hardening
      ↓
WAF / Detection

نه برعکس.

Logging برای شناسایی File Inclusion

Logging می‌تواند در Detection و Incident Response مفید باشد.

بهتر است Application رویدادهایی مانند Invalid Template Selection، File Mapping Failure، Rejected Filename، Path Validation Failure و تلاش برای انتخاب Resource خارج از Allowlist را ثبت کند.

اما Log نباید Secret، Session Token یا محتوای فایل حساس را ذخیره کند.

همچنین Full Internal Path نباید بی‌دلیل در Error Response کاربر نمایش داده شود.

Error Messageها را محدود کنید

نمایش خطای خام include() یا require() ممکن است مسیر داخلی Application را افشا کند.

Production Error باید برای کاربر عمومی باشد.

مثلاً:

صفحه موردنظر در دسترس نیست.

جزئیات فنی باید فقط در Log داخلی ثبت شوند.

Internal Path Disclosure ممکن است به مهاجم در درک ساختار Application کمک کند.

اگر LFI یا RFI پیدا شد چه کنیم؟

اولین اقدام این است که Sink آسیب‌پذیر شناسایی شود.

باید مشخص شود کدام ورودی روی Filename اثر می‌گذارد.

سپس باید بررسی شود:

File Inclusion از کجا انجام می‌شود؟

کاربر چه سطح دسترسی دارد؟

چه فایل‌هایی در Scope Process قابل دسترسی هستند؟

Remote Include فعال است یا خیر؟

آیا Vulnerability فقط Read/Include محلی ایجاد می‌کند یا پیامد بیشتری قابل اثبات است؟

سپس Code باید از Dynamic Filename به Mapping ثابت تغییر داده شود.

اگر Endpoint فوراً قابل Patch نیست، محدود کردن دسترسی یا غیرفعال کردن Feature می‌تواند Mitigation موقت باشد.

Incident Response برای LFI

اگر LFI در Production برای مدت نامعلومی وجود داشته است، باید احتمال سوءاستفاده بررسی شود.

تنها Patch کردن Function کافی نیست.

تیم امنیت باید مشخص کند Web Process به چه فایل‌هایی دسترسی داشته است.

Application Log، Reverse Proxy Log و WAF Log بررسی شوند.

اگر احتمال دسترسی به Credential وجود دارد، Secret Rotation باید در Scope Incident قرار گیرد.

اگر امکان Include فایل‌هایی وجود داشته که محتوا یا رفتار اجرایی داشته‌اند، بررسی عمیق‌تر Environment ضروری است.

Incident Response برای RFI

RFI بالقوه حساس‌تر است زیرا Resource خارجی وارد Environment می‌شود.

در صورت مشاهده شواهد سوءاستفاده باید علاوه بر Application Log، Network Log و Outbound Connectionها نیز بررسی شوند.

مواردی مانند Processهای غیرعادی، فایل‌های جدید، تغییر Configuration و Network Destinationهای ناشناخته باید براساس Incident Response Plan سازمان بررسی شوند.

هدف اصلی این است که مشخص شود:

آیا فقط Attempt رخ داده یا Code واقعاً تحت تأثیر قرار گرفته است؟

اشتباهات رایج در جلوگیری از LFI و RFI

تکیه بر Blocklist

مسدود کردن چند Keyword یا Character خاص معمولاً قابل اعتماد نیست.

روش بهتر Allowlist است.

دریافت Filename مستقیم از Query String

این طراحی از ابتدا Attack Surface ایجاد می‌کند.

Client باید Logical Identifier ارسال کند.

خاموش کردن Remote Include و تصور حل کامل مشکل

این تنظیم RFI کلاسیک را کاهش می‌دهد، اما LFI را حل نمی‌کند.

اعتماد به داده دیتابیس

Database منبع Trust نیست مگر منشأ داده مشخص و کنترل‌شده باشد.

دسترسی بیش از حد PHP Process

حتی LFI ساده در Process پرقدرت می‌تواند Exposure بیشتری ایجاد کند.

نمایش خطاهای PHP در Production

Path و Stack Trace می‌تواند اطلاعات داخلی افشا کند.

طراحی Template Loader عمومی

تابعی که هر Filename را دریافت و Include می‌کند باید با حساسیت زیادی بررسی شود.

اعتماد به WAF

WAF دفاع مکمل است، نه Remediation.

نبود تست Regression

پس از Patch باید آزمایش شود که مسیر ناامن مشابه در Endpointهای دیگر باقی نمانده باشد. LFI و RFI چه خطراتی دارند؟

چک‌لیست دفاعی جلوگیری از LFI و RFI

  • User Input را مستقیماً در include، require یا Template Loader استفاده نکنید؛ از شناسه و Mapping ثابت استفاده کنید؛ Templateها و فایل‌های مجاز را در Allowlist قرار دهید؛ Remote Include را در PHP غیرفعال نگه دارید؛ نیاز واقعی به allow_url_fopen را بررسی کنید؛ File Include Directory را ثابت و تحت کنترل Application قرار دهید؛ در مسیرهای دینامیک ضروری Canonicalization و Base Directory Check انجام دهید؛ فایل‌های Include را تا حد امکان خارج از Web Root نگه دارید؛ Process وب را با Least Privilege اجرا کنید؛ File Permissionها را محدود کنید؛ Errorهای خام PHP را در Production نمایش ندهید؛ Template و Language Loaderها را Code Review کنید؛ ورودی Database را خودکار Trusted فرض نکنید؛ در WordPress از Mapping و APIهای Core استفاده کنید و validate_file() را در سناریوهای مرتبط در نظر بگیرید؛ SAST را برای Source-to-Sink Flow اجرا کنید؛ تست DAST را فقط روی Environment مجاز انجام دهید؛ WAF را به‌عنوان لایه مکمل استفاده کنید؛ Logging برای File Selection Failure داشته باشید؛ PHP و Dependencyها را به‌روز نگه دارید؛ پس از اصلاح Vulnerability تست Regression انجام دهید.

معماری امن برای انتخاب صفحه

یکی از الگوهای مناسب می‌تواند چنین باشد:

HTTP Request:
page=profile

        ↓

Validation:
آیا profile در لیست صفحات مجاز است؟

        ↓

Server Mapping:
profile → templates/profile.php

        ↓

Trusted Include

در این ساختار Client هرگز Filename را نمی‌بیند و کنترل نمی‌کند.

این مدل به‌مراتب امن‌تر از:

HTTP Request
      ↓
Filename
      ↓
include()

است.

معماری امن برای سیستم چندزبانه

فرض کنید سایت چهار زبان دارد.

به‌جای ساخت Filename براساس String آزاد:

User Language
     ↓
Dynamic Filename

از Mapping استفاده کنید:

fa → language/fa.php
en → language/en.php
de → language/de.php
tr → language/tr.php

اگر مقدار ورودی در Mapping وجود نداشته باشد، Language پیش‌فرض بارگذاری شود.

معماری امن برای WordPress Plugin

یک Plugin ممکن است سه View داشته باشد:

settings
reports
account

روش مناسب آن است که هر View در یک آرایه داخلی به File مشخص Mapping شود.

Request فقط نام منطقی View را انتخاب کند.

بهتر است Plugin Filename خام را از $_GET یا $_POST دریافت و مستقیماً وارد Template Loader نکند.

WordPress همچنین تابع validate_file() را ارائه می‌کند که Filename و Path را در برابر قواعدی از جمله Directory Traversal و Allowed File List بررسی می‌کند.

اما استفاده از API امنیتی نباید جایگزین طراحی صحیح شود.

Code Review مخصوص LFI و RFI

هنگام Review پروژه PHP ابتدا تمام File Inclusion Sinkها را Inventory کنید.

سپس برای هر یک سؤال‌های زیر را پاسخ دهید:

ورودی Filename از کجا می‌آید؟

آیا مقدار تحت کنترل HTTP Request است؟

آیا Database Field قابل‌ویرایش روی آن اثر دارد؟

آیا URL خارجی قابل استفاده است؟

آیا Allowlist وجود دارد؟

آیا Allowlist واقعاً Exact Match است؟

آیا Mapping در Server انجام می‌شود؟

Application Process به چه فایل‌هایی دسترسی دارد؟

آیا Error Message مسیر واقعی را افشا می‌کند؟

آیا Feature مشابه دیگری نیز از همان Utility Function استفاده می‌کند؟

این بررسی معمولاً بسیار مؤثرتر از جست‌وجوی ساده چند Pattern است.

Severity آسیب‌پذیری LFI چگونه تعیین می‌شود؟

Severity باید براساس Evidence واقعی باشد.

موارد مهم عبارت‌اند از Authentication Requirement، دسترسی File System، فایل‌های قابل Include، Runtime Behavior، قابلیت خواندن Secret، امکان تأثیرگذاری روی فایل محلی و سطح Privilege سرویس.

یک LFI که تنها Administrator قابل‌اعتماد به آن دسترسی دارد و Process نیز محدود است با LFI عمومی روی Endpoint بدون Authentication یکسان نیست.

همچنین نباید صرف پیدا شدن LFI، RCE قطعی اعلام شود.

گزارش حرفه‌ای باید بنویسد چه رفتاری اثبات شده و چه پیامدهایی فقط بالقوه هستند.

Severity آسیب‌پذیری RFI چگونه تعیین می‌شود؟

در RFI نیز باید بررسی شود:

آیا Remote Include واقعاً فعال است؟

چه Protocolها یا Wrapperهایی مجاز هستند؟

آیا Resource خارجی وارد Runtime می‌شود؟

Endpoint نیازمند Authentication است؟

آیا Outbound Network Access محدود است؟

Process چه Permissionهایی دارد؟

صرف وجود یک Parameter به نام file یا template اثبات RFI نیست.

باید Data Flow و Runtime Behavior مشخص شود.

Egress Filtering و RFI

در معماری‌های امنیتی پیشرفته، Egress Filtering می‌تواند لایه دیگری از Defense in Depth باشد.

Application Server نباید بدون نیاز بتواند به هر مقصد اینترنتی Connection ایجاد کند.

اگر سرویس فقط به چند API مشخص نیاز دارد، Firewall یا Network Policy می‌تواند Outbound Destinationها را محدود کند.

این کنترل RFI را از ریشه برطرف نمی‌کند، اما می‌تواند اثر برخی ضعف‌ها را کاهش دهد.

چرا PHP Update مهم است؟

MITRE توصیه می‌کند از نسخه‌های جدید PHP استفاده شود، زیرا بسیاری از قابلیت‌های پرریسک قدیمی در نسخه‌های جدید محدود یا حذف شده‌اند.

نمونه مهم همین allow_url_include است که از PHP 7.4 Deprecated شده و به‌صورت پیش‌فرض غیرفعال است.

با این حال Update به‌تنهایی Vulnerability منطقی زیر را برطرف نمی‌کند:

Untrusted filename → include()

Application Code نیز باید اصلاح شود.

Defense in Depth برای LFI و RFI

یک طراحی حرفه‌ای نباید به یک کنترل تکیه کند.

لایه اول باید حذف Dynamic Include غیرضروری باشد.

لایه دوم Allowlist و Mapping است.

لایه سوم File System Boundary و Permission است.

لایه چهارم PHP Hardening است.

لایه پنجم Network Egress Control است.

لایه ششم Error Handling، Logging و Monitoring است.

لایه هفتم SAST، DAST و Code Review است.

وجود چند لایه باعث می‌شود شکست یک کنترل الزاماً به Incident جدی تبدیل نشود.

سؤالات متداول درباره LFI و RFI

LFI چیست؟

LFI یا Local File Inclusion آسیب‌پذیری‌ای است که در آن برنامه به‌دلیل کنترل ناکافی Filename یا Path، یک فایل موجود روی همان سرور را به‌صورت ناخواسته در Application Include می‌کند. OWASP این ضعف را با Dynamic File Inclusion ناامن مرتبط می‌داند.

RFI چیست؟

RFI یا Remote File Inclusion زمانی رخ می‌دهد که Application بتواند Resource راه‌دور را از طریق مکانیزم Include ناامن وارد پردازش خود کند. در PHP این موضوع به Configuration و قابلیت URL Include نیز وابسته است.

تفاوت اصلی LFI و RFI چیست؟

LFI به فایل موجود روی سرور هدف مربوط است، درحالی‌که RFI Resource را از محل راه‌دور دریافت می‌کند. هر دو معمولاً از کنترل ناکافی ورودی مورد استفاده برای File Inclusion ناشی می‌شوند.

آیا LFI همان Path Traversal است؟

خیر. Path Traversal مربوط به خروج Path از محدوده مجاز است، اما LFI مربوط به Include شدن فایل محلی در Application است. Path Traversal می‌تواند یکی از راه‌های رسیدن به LFI باشد.

آیا هر LFI باعث RCE می‌شود؟

خیر. پیامد LFI به Runtime، نوع فایل، Permission و Environment بستگی دارد. اجرای کد در برخی شرایط ممکن است، اما نباید بدون Evidence برای تمام LFIها ادعا شود.

آیا RFI همیشه باعث اجرای کد می‌شود؟

خیر. شدت RFI نیز به نحوه Include، Interpreter و Configuration بستگی دارد. با این حال امکان وارد کردن Resource خارجی باعث می‌شود RFI بالقوه بسیار جدی باشد.

CWE مربوط به LFI و RFI چیست؟

برای PHP، MITRE ضعف Improper Control of Filename for Include/Require Statement را با شناسه CWE-98 ثبت کرده است و RFI و LFI را در توضیحات آن پوشش می‌دهد. LFI بسته به Root Cause ممکن است با Path Traversal و CWEهای مرتبط با کنترل Path نیز ارتباط داشته باشد.

آیا allow_url_include در PHP به‌صورت پیش‌فرض فعال است؟

خیر. براساس مستندات رسمی PHP، مقدار پیش‌فرض allow_url_include برابر 0 است و این Directive از PHP 7.4 Deprecated شده است.

آیا خاموش کردن allow_url_include برای جلوگیری از File Inclusion کافی است؟

خیر. این تنظیم می‌تواند RFI کلاسیک مبتنی بر URL Include را محدود کند، اما LFI یا Dynamic Local File Inclusion را برطرف نمی‌کند. Secure Coding همچنان ضروری است.

بهترین روش جلوگیری از LFI چیست؟

بهترین روش این است که Filename از User Input ساخته نشود. Client فقط Identifier محدود ارسال کند و Server آن را از طریق Allowlist به فایل ثابت Mapping کند.

بهترین روش جلوگیری از RFI چیست؟

علاوه بر جلوگیری از Dynamic Include، allow_url_include باید غیرفعال بماند، Remote Resourceها نباید به‌عنوان Code Include شوند و Egress Access سرور نیز براساس نیاز واقعی محدود شود.

آیا WAF از LFI و RFI جلوگیری می‌کند؟

WAF می‌تواند برخی درخواست‌های مشکوک را شناسایی کند، اما جایگزین اصلاح Code نیست. کنترل اصلی باید در Application و Trust Boundary اعمال شود.

آیا LFI در وردپرس ممکن است؟

بله. اگر Plugin یا Theme سفارشی Filename یا Template را براساس User Input به شکل ناامن Load کند، File Inclusion می‌تواند مطرح شود. WordPress ابزارهایی مانند validate_file() برای Validation فایل و Path دارد.

آیا get_template_part در وردپرس ناامن است؟

خود get_template_part() یک قابلیت استاندارد WordPress است و وجود آن به معنی Vulnerability نیست. مسئله اصلی منشأ $slug و $name و نحوه کنترل مقادیر است. مستندات رسمی توضیح می‌دهند که این تابع Template Partهای نام‌گذاری‌شده را بارگذاری می‌کند.

آیا Filename Sanitization برای جلوگیری از LFI کافی است؟

معمولاً خیر. Sanitization ممکن است Characterهای خاص را تغییر دهد، اما راهکار قوی‌تر Allowlist و Mapping به Filenameهای ثابت است.

آیا LFI فقط در PHP وجود دارد؟

خیر. مفهوم Dynamic Local File Inclusion یا Template Loading ناامن می‌تواند در فناوری‌های مختلف ظاهر شود، هرچند اصطلاح LFI و CWE-98 به‌شدت با PHP شناخته شده‌اند.

جمع‌بندی

LFI و RFI دو عضو مهم خانواده آسیب‌پذیری‌های File Inclusion هستند که ریشه مشترک آنها شکسته شدن مرز میان ورودی غیرقابل‌اعتماد و فایل مورد استفاده توسط Application است.

در Local File Inclusion یا LFI، Application یک فایل موجود در محیط محلی Server را به‌شکل ناخواسته Include می‌کند.

در Remote File Inclusion یا RFI، Resource مورد استفاده از یک محل خارجی دریافت می‌شود.

این تفاوت باعث می‌شود RFI معمولاً به Environment و تنظیماتی که Remote Include را ممکن می‌کنند نیز وابسته باشد.

در PHP، Directive مربوط به allow_url_include به‌صورت پیش‌فرض خاموش است و از PHP 7.4 Deprecated شده است؛ بنابراین RFI کلاسیک در Environmentهای مدرن بسیار محدودتر از گذشته است. با این حال Dynamic File Inclusion ناامن همچنان یک Anti-Pattern امنیتی جدی محسوب می‌شود.

LFI نیز نباید صرفاً «خواندن یک فایل» تلقی شود.

رفتار Include با Arbitrary File Read تفاوت دارد و بسته به Runtime و محتوای فایل می‌تواند پیامدهای متفاوتی ایجاد کند.

همچنین LFI رابطه نزدیکی با Path Traversal دارد، اما این دو مفهوم یکسان نیستند. Path Traversal کنترل مسیر را تحت تأثیر قرار می‌دهد، درحالی‌که LFI نتیجه Include شدن یک فایل محلی در Application است.

مهم‌ترین روش جلوگیری از LFI و RFI بسیار ساده است:

User Input هرگز نباید Filename واقعی مورد استفاده در include، require یا Template Loader را تعیین کند.

به‌جای Filename باید از Logical Identifier استفاده شود و Application در سمت Server آن Identifier را از طریق Allowlist به فایل ثابت Mapping کند.

در کنار آن، غیرفعال نگه داشتن Remote Include، محدود کردن File Permissionها، Least Privilege، نگهداری Include Fileها خارج از Web Root، محدود کردن Outbound Network Access، استفاده از APIهای امن Framework، مدیریت صحیح Errorها و اجرای Code Review و SAST و DAST می‌توانند Defense in Depth مناسبی ایجاد کنند.

در WordPress نیز Pluginها و Themeها باید از دریافت مستقیم نام Template یا فایل از Request خودداری کنند و در سناریوهای مرتبط از APIهای Core و کنترل‌هایی مانند validate_file() استفاده کنند.

در نهایت مهم‌ترین سؤال هنگام بررسی یک File Loader این است:

«آیا Application خودش تعیین می‌کند چه فایلی بارگذاری شود، یا بخشی از این تصمیم را به User Input واگذار کرده است؟»

اگر User Input بتواند Filename یا Resource مورد Include را کنترل کند، آن بخش باید از نظر LFI و RFI با دقت مورد Code Review و Hardening قرار گیرد.

مطالب مرتبط