عنوان:

‫شبیه سازی عملکرد پوشه App_Data در IIS بر روی لینوکس توسط nginx


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۰۳ ۰۸:۰۵
آدرس: www.dntips.ir
پوشه App_Data در IIS یک ویژگی بسیار کاربردی است که به صورت پیش‌فرض از محتویات آن در برابر دسترسی مستقیم از طریق وب محافظت می‌کند. خوشبختانه، شبیه‌سازی این رفتار و حتی پیاده‌سازی روش‌های امن‌تر در لینوکس با NGINX بسیار ساده است. دو رویکرد اصلی و استاندارد برای این کار وجود دارد.

روش اول: جداسازی فیزیکی (رویکرد پیشنهادی و امن‌تر)
این روش، استاندارد طلایی و بهترین رویه در محیط لینوکس محسوب می‌شود. فلسفه آن ساده است: "چیزی که در معرض دید عموم نیست، هرگز نباید در پوشه عمومی قرار گیرد."
در این روش، ما پوشه داده‌های حساس خود را به طور کامل خارج از ریشه وب (Web Root) قرار می‌دهیم.
ساختار پوشه‌ها به این شکل خواهد بود:
/var/www/my-awesome-app/
├── my-awesome-app.dll        # فایل اجرایی اپلیکیشن
├── appsettings.json          # فایل تنظیمات
├── ... (فایل‌های دیگر برنامه)
│
├── AppData/                  # <-- پوشه داده‌های محافظت شده شما
│   ├── sensitive-data.xml
│   └── local-database.sqlite
│
└── wwwroot/                  # <-- ریشه وب (فقط فایل‌های عمومی)
    ├── css/
    ├── js/
    ├── images/
    └── index.html

چگونه کار می‌کند؟
۱. تنظیمات NGINX: در فایل کانفیگ NGINX، شما root یا ریشه وب را به پوشه wwwroot اشاره می‌دهید:
server {
    # ...
    root /var/www/my-awesome-app/wwwroot;
    # ...
}
این دستور به NGINX می‌گوید: "تو فقط مسئول سرو کردن فایل‌هایی هستی که داخل پوشه /var/www/my-awesome-app/wwwroot قرار دارند و به هیچ جای دیگری دسترسی نداری."
نتیجه: حالا اگر کاربری تلاش کند به آدرس http://your-domain.com/AppData/sensitive-data.xml دسترسی پیدا کند، NGINX هرگز آن فایل را پیدا نخواهد کرد، چون از نظر فیزیکی در محدوده دسترسی آن نیست. NGINX یک خطای 404 Not Found برمی‌گرداند. این روش به طور کامل جلوی هرگونه دسترسی وب به این پوشه را می‌گیرد.

دسترسی اپلیکیشن ASP.NET Core: اپلیکیشن شما که از مسیر /var/www/my-awesome-app/ اجرا می‌شود، به راحتی می‌تواند با استفاده از مسیرهای نسبی (./AppData/sensitive-data.xml) یا مسیرهای مطلق، به این پوشه دسترسی داشته باشد، فایل بخواند یا در آن بنویسد.

چرا این روش بهترین است؟
  • امنیت ذاتی (Secure by Design): امنیت شما به یک قانون در کانفیگ وابسته نیست، بلکه بر اساس ساختار فیزیکی و منطقی فایل‌ها بنا شده است. یک اشتباه در کانفیگ NGINX باعث لو رفتن داده‌های شما نمی‌شود.
  • جداسازی کامل: فایل‌های عمومی (Public Assets) از فایل‌های خصوصی و منطق برنامه (Private Assets & Logic) به طور کامل جدا هستند.

روش دوم: مسدودسازی با قانون NGINX (رویکرد مشابه IIS)
این روش دقیقاً رفتار IIS با App_Data را شبیه‌سازی می‌کند. در این حالت، شما پوشه داده‌ها را داخل ریشه وب قرار می‌دهید، اما با یک قانون صریح در NGINX، جلوی دسترسی به آن را می‌گیرید.
ساختار پوشه‌ها در این روش:
/var/www/my-awesome-app/wwwroot/
├── css/
├── js/
├── images/
├── index.html
│
└── AppData/                  # <-- پوشه داده‌ها داخل ریشه وب
    ├── sensitive-data.xml
    └── local-database.sqlite

چگونه کار می‌کند؟
شما یک بلوک location ویژه به فایل کانفیگ NGINX خود اضافه می‌کنید تا تمام درخواست‌ها به این پوشه را مسدود کند.
server {
    root /var/www/my-awesome-app/wwwroot;
    index index.html index.htm;
    server_name your-domain.com;

    # ... سایر تنظیمات

    # قانون کلیدی برای محافظت از پوشه AppData
    location ~ ^/AppData/ {
        # تمام دسترسی‌ها را مسدود کن
        deny all;

        # بازگرداندن خطای 404 بهتر از 403 (Forbidden) است
        # چون حتی وجود داشتن چنین پوشه‌ای را هم از مهاجم مخفی می‌کند.
        return 404;
    }

    location / {
        try_files $uri @proxy; # ارسال سایر درخواست‌ها به اپلیکیشن
    }

    # ...
}
توضیح قانون:
  • location ~ ^/AppData/: این دستور به NGINX می‌گوید: "یک قانون ویژه برای تمام آدرس‌هایی که با /AppData/ شروع می‌شوند، در نظر بگیر." (علامت ~ برای تطبیق با عبارات باقاعده و ^ برای مشخص کردن ابتدای مسیر است).
  • deny all;: این دستور صریحاً به NGINX می‌گوید که دسترسی به این مسیر را برای همه مسدود کند.
  • return 404;: این دستور باعث می‌شود که NGINX به جای خطای پیش‌فرض 403 Forbidden، خطای 404 Not Found را به کاربر نمایش دهد. این یک مزیت امنیتی کوچک دارد، زیرا به یک مهاجم بالقوه حتی اطلاع نمی‌دهد که چنین پوشه‌ای وجود دارد.

خلاصه و توصیه نهایی
ویژگیروش ۱ (جداسازی فیزیکی)روش ۲ (قانون NGINX)
امنیتبسیار بالا (ذاتی و ساختاری)بالا (وابسته به صحت کانفیگ)
پیچیدگیکم (فقط نیاز به رعایت ساختار پوشه)کم (فقط نیاز به افزودن چند خط کانفیگ)
شباهت به IISکمزیاد (شبیه‌سازی دقیق رفتار App_Data)
توصیهپیشنهاد اصلی برای پروژه‌های جدیدجایگزین خوب، خصوصاً برای انتقال پروژه‌های موجود

توصیه نهایی: اگر در حال شروع یک پروژه جدید هستید، حتماً از روش اول (جداسازی فیزیکی) استفاده کنید. این روش تمیزتر، امن‌تر و با فلسفه طراحی سیستم‌های لینوکسی سازگارتر است. اگر در حال انتقال یک پروژه قدیمی هستید که از قبل ساختار پوشه App_Data را داخل ریشه وب دارد، روش دوم (قانون NGINX) یک راه حل سریع، مؤثر و کاملاً قابل قبول است.

نظرات

  • وحید نصیری در ۱۴۰۴/۰۴/۰۳ ۰۸:۰۹
    یک نکته‌ی تکمیلی: روش مسدودسازی دسترسی به فایل‌های حساس در NGINX

    وب‌سایت شما مانند یک فروشگاه است. شما می‌خواهید مشتریان ویترین (صفحات HTML)، دکوراسیون (فایل‌های CSS) و محصولات قابل مشاهده (تصاویر) را ببینند. اما شما هرگز دوست ندارید یک مشتری بتواند وارد انبار، دفتر مدیریت یا اتاق گاوصندوق شما شود! در دنیای وب، فایل‌هایی مانند سورس کد (.cs, .sln)، پایگاه داده (.sqlite, .db)، فایل‌های باینری برنامه (.dll, .exe) و پوشه سورس کنترل شما (.git) دقیقاً مانند انبار و اتاق گاوصندوق شما هستند. به صورت پیش‌فرض، اگر این فایل‌ها به نحوی داخل پوشه عمومی شما قرار گیرند، ممکن است یک کاربر بتواند با وارد کردن آدرس مستقیم، آن‌ها را دانلود کند. این یک فاجعه امنیتی است. در ادامه یاد می‌گیریم چگونه با استفاده از قوانین قدرتمند NGINX، درب این مکان‌های حساس را برای همیشه قفل کنیم.

    بخش اول: مسدودسازی دسترسی بر اساس پسوند فایل
    هدف: ما می‌خواهیم جلوی دسترسی مستقیم به هر فایلی با پسوندهای حساس را بگیریم، صرف نظر از اینکه در کدام پوشه قرار دارد.
    ابزار کار: یک بلوک location با استفاده از عبارات باقاعده (Regular Expression یا Regex).
    این قطعه کد را باید داخل بلوک server در فایل کانفیگ سایت خود قرار دهید.
    # این بلوک باید داخل بلوک server شما قرار گیرد
    
    # ===================================================================
    # قانون امنیتی: مسدود کردن دسترسی مستقیم به پسوندهای حساس و خطرناک
    # ===================================================================
    location ~* \.(git|sqlite|exe|dll|db|config|log|sln|cs|csproj|user|json)$ {
        # تمام دسترسی‌ها را مسدود کن
        deny all;
    
        # رویکرد بهتر: بازگرداندن خطای 404 به جای 403 (Forbidden)
        # این کار حتی وجود داشتن چنین فایلی را هم از مهاجم مخفی می‌کند.
        # return 404;
    }
    کالبدشکافی این قانون:
    • location ~*: این به NGINX می‌گوید که یک قانون مبتنی بر "عبارت باقاعده" (~) و "بدون حساسیت به بزرگی و کوچکی حروف" (*) را اعمال کند. یعنی .DLL و .dll هر دو مسدود می‌شوند.
    • \.: علامت \ (بک‌اسلش) کاراکتر بعدی را "بی‌اثر" می‌کند. از آنجایی که . (نقطه) در عبارات باقاعده معنای خاصی ("هر کاراکتری") دارد، ما با \. می‌گوییم که منظورمان دقیقاً خود کاراکتر "نقطه" است.
    • (git|sqlite|...|json): پرانتزها یک گروه ایجاد می‌کنند و علامت | (پایپ) به معنای "یا" (OR) است. پس این بخش یعنی: "پسوند git یا sqlite یا exe یا ...". شما می‌توانید هر پسوند دیگری را به این لیست اضافه کنید.
    • $: این علامت در عبارات باقاعده به معنای "انتهای رشته" است. این بخش بسیار مهم است و تضمین می‌کند که قانون فقط برای فایل‌هایی اعمال شود که نامشان با این پسوندها تمام می‌شود.

    deny all در مقابل return 404:
    • deny all;: به کاربر خطای 403 Forbidden را نشان می‌دهد. این تنظیم به مهاجم می‌گوید "این فایل وجود دارد، اما تو اجازه دسترسی به آن را نداری."
    • return 404;: به کاربر خطای 404 Not Found را نشان می‌دهد. این به مهاجم می‌گوید "چنین فایلی اصلاً وجود ندارد." این رویکرد کمی امن‌تر است، زیرا اطلاعات کمتری در مورد ساختار فایل‌های شما به بیرون درز می‌دهد (این یک شکل از امنیت از طریق پنهان‌کاری یا Security through Obscurity است).

    بخش دوم: مسدودسازی دسترسی به فایل‌های مخفی (Dotfiles)
    هدف: در دنیای لینوکس، فایل‌ها و پوشه‌هایی که نامشان با نقطه شروع می‌شود (مانند .git, .env, .htaccess) به صورت پیش‌فرض "مخفی" هستند و معمولاً حاوی تنظیمات حساس یا اطلاعات محرمانه می‌باشند. ما باید دسترسی به تمام آن‌ها را از طریق وب مسدود کنیم.

    ابزار کار: یک بلوک location دیگر با یک عبارت باقاعده ساده.
    این قطعه کد را هم مانند قانون قبلی، داخل بلوک server خود قرار دهید.
    # ===================================================================
    # قانون امنیتی: مسدود کردن دسترسی به فایل‌ها و پوشه‌هایی که با نقطه شروع می‌شوند
    # ===================================================================
    location ~ /\. {
        deny all;
        # return 404;
    }
    کالبدشکافی این قانون:
    • location ~: باز هم یک قانون مبتنی بر عبارت باقاعده.
    • /\.: این عبارت ساده و قدرتمند به دنبال هر الگویی می‌گردد که شامل یک / و بلافاصله پس از آن یک . باشد. این قانون به طور مؤثری تمام فایل‌ها و پوشه‌های مخفی در تمام سطوح را پوشش می‌دهد. برای مثال، هم درخواست http://domain.com/.env و هم http://domain.com/sub/folder/.htaccess توسط این قانون مسدود خواهد شد.

    جمع‌بندی: قرار دادن قوانین در جای درست
    این بلوک‌های location باید داخل بلوک server اصلی شما و در کنار سایر بلوک‌ها قرار گیرند. NGINX به اندازه کافی هوشمند است که قبل از اعمال قوانین عمومی (مانند location /)، ابتدا این قوانین خاص‌تر را بررسی کند.

    یک مثال از ساختار نهایی:
    server {
        listen 80;
        server_name your-domain.com;
        root /var/www/my-app/wwwroot;
    
        # >> قانون اول: مسدودسازی فایل‌های مخفی
        location ~ /\. {
            return 404;
        }
    
        # >> قانون دوم: مسدودسازی پسوندهای حساس
        location ~* \.(git|sqlite|exe|dll|db|config|log)$ {
            return 404;
        }
    
        # قانون اصلی برای اپلیکیشن شما
        location / {
            try_files $uri @proxy;
        }
        
        # ... سایر تنظیمات و location پراکسی
    }
    با پیاده‌سازی این دو قانون ساده، شما یک لایه دفاعی بسیار مهم را به وب سرور خود اضافه کرده و جلوی یکی از رایج‌ترین و خطرناک‌ترین بردارهای حمله، یعنی نشت اطلاعات حساس، را گرفته‌اید. این دو قانون از جمله تنظیمات ضروری برای هر سرور Production هستند.