آن خط کدی که درِ سرور را باز کرد

چند سال پیش، پرونده‌ای به من ارجاع داده شد که در آن سایت یک شرکت متوسط به‌طور مرموزی به یک سرور خارجی متصل می‌شد. بعد از بررسی، علت را در یک خط سادهٔ PHP پیدا کردم: کدی که از پارامتر URL برای بارگذاری فایل استفاده می‌کرد، بدون هیچ اعتبارسنجی. این همان آسیب‌پذیری File Inclusion بود که در نسخهٔ RFI ظاهر شده بود. آن روز برای من تأکیدی دوباره بر این حقیقت بود که در بسیاری از حملات وب، مشکل از یک خط کد ناشی می‌شود، نه از یک نفوذ پیچیده. در این مقاله، تفاوت RFI و LFI و راهکارهای دفاع در برابر آن‌ها را با هم مرور می‌کنیم. اگر تازه با مفهوم آسیب‌پذیری آشنا می‌شوید، پیشنهاد می‌کنم ابتدا آسیب‌پذیری وب چیست و چگونه شناسایی می‌شود را بخوانید.

File Inclusion چیست؟

File Inclusion به دسته‌ای از آسیب‌پذیری‌ها گفته می‌شود که در آن مهاجم می‌تواند فایلی را در سرور بارگذاری یا اجرا کند، بدون اینکه سایت برای این کار مجوز داده باشد. این دسته، به دو زیردسته تقسیم می‌شود: Remote File Inclusion یا RFI که فایل‌های خارجی را بارگذاری می‌کند، و Local File Inclusion یا LFI که فایل‌های داخلی سرور را هدف می‌گیرد. در هر دو حالت، علت اصلی یکسان است: استفاده از ورودی کاربر برای تعیین مسیر فایل، بدون اعتبارسنجی مناسب.

این نوع آسیب‌پذیری به‌ویژه در زبان‌های وب‌محور مثل PHP رایج است، چون توابعی مثل include و require ورودی را به‌صورت مسیر فایل تفسیر می‌کنند. اگر این ورودی از سمت کاربر بیاید و پاک‌سازی نشود، مهاجم می‌تواند مسیر دلخواه خودش را وارد کند. در انواع آسیب‌پذیری‌های رایج وب این نوع را در کنار سایر آسیب‌پذیری‌های اصلی فهرست کرده‌ام.

LFI یا Local File Inclusion چیست؟

LFI یا Local File Inclusion به مهاجم اجازه می‌دهد فایل‌هایی که روی خودِ سرور شما قرار دارند، بارگذاری کند. مثلاً اگر سایت شما کدی مثل include($_GET["page"].".php") داشته باشد، مهاجم می‌تواند با دستکاری پارامتر page، فایل‌های حساس سرور مثل /etc/passwd را بارگذاری کند. اگر سایت شما به‌درستی پیکربندی نشده باشد، این فایل‌ها می‌توانند به افشای اطلاعات حساس منجر شوند.

در حالت پیشرفته، LFI می‌تواند به اجرای کد هم منجر شود. اگر مهاجم بتواند فایلی مثل لاگ سرور یا فایل session را بارگذاری کند و در آن کد PHP قرار داده باشد، آن کد اجرا می‌شود. این سناریو به LFI-to-RCE معروف است و یکی از خطرناک‌ترین حالات LFI است.

RFI یا Remote File Inclusion چیست؟

RFI یا Remote File Inclusion به مهاجم اجازه می‌دهد فایلی از یک سرور خارجی را در سایت شما بارگذاری و اجرا کند. این نوع آسیب‌پذیری خطرناک‌تر از LFI است، چون مهاجم می‌تواند کد دلخواه خودش را روی یک سرور خارجی میزبانی کند و سپس سایت شما را وادار به اجرای آن کند. اگر سایت شما به RFI آسیب‌پذیر باشد، به‌طور مستقیم کد مخرب اجرا می‌شود و این می‌تواند به نفوذ کامل سرور منجر شود.

خوشبختانه، در نسخه‌های مدرن PHP گزینهٔ allow_url_include به‌صورت پیش‌فرض خاموش است و این باعث می‌شود که RFI بسیار کمتر رخ دهد. اما در پروژه‌های قدیمی یا افزونه‌های بدکد، هنوز این نوع آسیب‌پذیری دیده می‌شود.

تفاوت‌های کلیدی RFI و LFI

شاید در نگاه اول RFI و LFI شبیه هم به نظر برسند، اما تفاوت‌های مهمی دارند که بر استراتژی دفاع اثر می‌گذارد:

  • منبع فایل: در LFI، فایل از روی سرور خودتان بارگذاری می‌شود. در RFI، فایل از یک سرور خارجی می‌آید.
  • سطح دسترسی موردنیاز: در RFI، مهاجم نیازی به دسترسی به سرور شما ندارد. فقط کافی است سرور خارجی خودش را کنترل کند. در LFI، مهاجم به فایل‌های سرور شما دسترسی دارد اما باید فایل مناسب را پیدا کند.
  • پیامد: RFI معمولاً به اجرای کد مستقیم منجر می‌شود. LFI ابتدا به افشای اطلاعات منجر می‌شود و در حالت پیشرفته، ممکن است به اجرای کد هم برسد.
  • سطح دفاع: دفاع در برابر LFI ساده‌تر است چون فقط باید مسیر فایل را محدود کنید. دفاع در برابر RFI نیازمند مسدودسازی بارگذاری از منابع خارجی است.
  • نیاز به پیکربندی خاص: RFI نیازمند فعال بودن گزینه‌ای مثل allow_url_include در PHP است، در حالی که LFI همیشه ممکن است.

این تفاوت‌ها نشان می‌دهد که هرچند ریشهٔ هر دو آسیب‌پذیری یکسان است، اما استراتژی دفاعی متفاوتی نیاز دارند. اگر به‌دنبال درک عمیق‌تر انواع آسیب‌پذیری هستید، فهرست انواع آسیب‌پذیری‌های رایج وب نقطهٔ شروع خوبی است.

نمونه‌ای از کد آسیب‌پذیر

در نظر بگیرید کد زیر را:

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

این کد با هر درخواست، یک فایل PHP را بر اساس پارامتر page بارگذاری می‌کند. اگر کاربر پارامتر page را به مقدار دلخواه تغییر دهد، می‌تواند فایل‌های مختلف را بارگذاری کند. در بدترین حالت، مهاجم می‌تواند از طریق RFI یک فایل خارجی را به‌عنوان مقدار پارامتر وارد کند و اجرای کد را انجام دهد. همین یک خط ساده، نمونهٔ کلاسیک آسیب‌پذیری File Inclusion است.

روش‌های دفاع در برابر RFI و LFI

دفاع در برابر این آسیب‌پذیری‌ها، بیشتر از هر چیز به انضباط کدنویسی نیاز دارد. چند اصل اساسی که در پروژه‌های خودم رعایت می‌کنم:

  • استفاده از فهرست سفید: به‌جای بارگذاری فایل بر اساس ورودی کاربر، فهرست ثابتی از فایل‌های مجاز تعریف کنید و فقط آن‌ها را بارگذاری کنید.
  • عدم استفاده از include با ورودی کاربر: هرگز مسیر فایل را از ورودی کاربر نسازید. اگر نیاز دارید فایلی را بر اساس پارامتر بارگذاری کنید، آن پارامتر باید فقط یک شناسهٔ عددی یا کلید ثابت باشد.
  • غیرفعال‌سازی allow_url_include: در php.ini مطمئن شوید که allow_url_include = Off است. این تنظیم، RFI را در بیشتر موارد مسدود می‌کند.
  • محدودسازی دایرکتوری: از open_basedir در PHP استفاده کنید تا دسترسی فایل به دایرکتوری‌های خاص محدود شود.
  • اعتبارسنجی ورودی: هر ورودی که برای ساخت مسیر فایل استفاده می‌شود، باید به‌دقت اعتبارسنجی شود.
  • پایش و لاگ: لاگ‌های سرور را برای درخواست‌هایی که مسیرهای غیرعادی دارند بررسی کنید.

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

RFI و LFI در وردپرس

در هستهٔ وردپرس، این نوع آسیب‌پذیری‌ها به‌طور جدی مدیریت می‌شوند و به‌ندرت دیده می‌شوند. اما در افزونه‌ها و قالب‌های ثالث، این نوع آسیب‌پذیری هنوز هم گزارش می‌شود. علت اصلی، استفادهٔ نادرست از توابع include یا require در افزونه‌هاست که گاهی ورودی کاربر را به‌طور مستقیم به این توابع پاس می‌دهند.

اگر از افزونه‌های ناشناخته یا نال استفاده می‌کنید، احتمال بیشتری وجود دارد که این نوع آسیب‌پذیری در آن‌ها باشد. فهرست بهترین افزونه‌های امنیتی وردپرس می‌تواند به شما در انتخاب افزونهٔ امن کمک کند. برای درک چرا وردپرس هدف این نوع حملات است، چرا وردپرس هدف حملات سایبری است تحلیل عمیقی ارائه می‌دهد. مستندات ویکی‌پدیا در مورد File inclusion vulnerability هم اطلاعات تخصصی خوبی دارد.

پیامدهای نفوذ از طریق RFI و LFI

پیامدهای این نوع آسیب‌پذیری می‌تواند بسیار گسترده باشد:

  • افشای اطلاعات حساس مثل فایل‌های پیکربندی و کلمات عبور
  • اجرای کد دلخواه و نفوذ به سرور
  • نصب بک‌دور برای دسترسی مداوم
  • خواندن فایل‌های خصوصی مشتریان
  • تخریب داده‌های سایت
  • استفاده از سرور شما برای حملات بعدی

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

ابزارهای شناسایی RFI و LFI

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

آیا RFI در PHP مدرن هنوز رخ می‌دهد؟

در نسخه‌های مدرن PHP، گزینهٔ allow_url_include به‌طور پیش‌فرض خاموش است و همین باعث می‌شود که RFI بسیار کمتر رخ دهد. اما این به‌معنای ناپدید شدن کامل RFI نیست. مهاجمان می‌توانند از ترفندهای دیگر مثل استفاده از data:// یا php://input برای بارگذاری کد از منابع دیگر استفاده کنند. همچنین، در هاست‌هایی که پیکربندی PHP قدیمی است، احتمال رخ دادن RFI بیشتر است.

نتیجه این است که هنوز هم باید در برابر RFI هوشیار بود. غیرفعال کردن allow_url_include کافی نیست؛ بلکه باید اصول کلی دفاع در برابر File Inclusion هم رعایت شود. اگر با مفاهیم امنیت وب آشنا نیستید، پیشنهاد می‌کنم امنیت وب چیست و چه اصولی دارد را بخوانید.

پرسش‌های پرتکرار دربارهٔ RFI و LFI

آیا RFI و LFI فقط در PHP رخ می‌دهند؟ نه. هرچند PHP رایج‌ترین بستر است، اما این نوع آسیب‌پذیری در زبان‌های دیگر هم ممکن است. هرجا کدی برای بارگذاری فایل از ورودی کاربر استفاده کند، احتمال این نوع آسیب‌پذیری وجود دارد.

آیا LFI همیشه خطرناک است؟ حتی LFI محدود هم خطرناک است، چون می‌تواند اطلاعات حساس را افشا کند. اگر با سایر آسیب‌پذیری‌ها ترکیب شود، ممکن است به اجرای کد منجر شود.

آیا افزونهٔ امنیتی این آسیب‌پذیری را می‌بندد؟ افزونهٔ امنیتی می‌تواند برخی از درخواست‌های مشکوک را مسدود کند، اما نمی‌تواند جایگزین کد سالم شود. اگر کد سایت یا افزونه‌ای آسیب‌پذیر باشد، هیچ ابزار امنیتی به‌تنهایی نمی‌تواند مشکل را برطرف کند.

چطور بفهمم سایت من به RFI یا LFI آسیب‌پذیر است؟ بهترین راه، بررسی کد افزونه‌ها و قالب‌های استفاده‌شده است. اگر در کدهای خودتان از include یا require با ورودی کاربر استفاده می‌کنید، نیازمند بازبینی فوری هستید. استفاده از اسکنرهای آسیب‌پذیری هم کمک‌کننده است.

آیا برای وب‌سایت وردپرسی هم LFI خطرناک است؟ بله. حتی اگر هستهٔ وردپرس سالم باشد، یک افزونهٔ آسیب‌پذیر می‌تواند کافی برای ایجاد این نوع نفوذ باشد.

نگاه پایانی: یک خط کد، همه‌چیز را تعیین می‌کند

RFI و LFI نمونه‌های بارزی از این حقیقت هستند که در امنیت وب، یک خط کد می‌تواند تمام سیستم را به خطر بیندازد. تفاوت این دو آسیب‌پذیری در منبع فایل و سطح پیچیدگی حمله است، اما ریشهٔ مشترک‌شان عدم اعتبارسنجی ورودی است. خبر خوب این است که دفاع در برابر هر دو، با اصولی ساده و مشخص قابل انجام است. اگر توسعه‌دهنده هستید، از توابع پاک‌سازی و فهرست سفید استفاده کنید. اگر مدیر سایت هستید، از افزونه‌های معتبر استفاده کنید و به‌طور منظم کد آن‌ها را بررسی کنید. اگر تجربه‌ای از مواجهه با RFI یا LFI دارید یا سؤالی دربارهٔ نحوهٔ دفاع در برابر آن دارید، در دیدگاه‌ها بنویسید؛ تجربهٔ شما می‌تواند به دیگران کمک کند.