عنوان:

‫درک هدرهای HTTP متادیتای فچ (Fetch Metadata)


نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۵/۰۸ ۰۸:۲۵
آدرس: www.dntips.ir
چکیده: با پیچیده‌تر شدن تهدیدات امنیتی در بستر وب، مکانیزم‌های سنتی مانند توکن‌های ضد جعل درخواست سمت سرور (Anti-CSRF Tokens) یا کوکی‌های SameSite به تنهایی برای مقابله با حملات پیشرفته کافی نیستند. مشخصه Fetch Metadata HTTP Request Headers که از سال ۲۰۱۹ توسط W3C معرفی شده و در سال‌های اخیر به پختگی کامل رسیده است، چارچوبی نوین ارائه می‌دهد. در این چارچوب، مرورگر همراه با هر درخواست HTTP، متاداده‌هایی شامل مبدأ، هدف و نحوه شکل‌گیری درخواست ارسال می‌کند. این مقاله به بررسی ساختار و کاربرد ۴ هدر اصلی یعنی Sec-Fetch-Site ،Sec-Fetch-Dest ،Sec-Fetch-Mode و Sec-Fetch-User می‌پردازد. همچنین، نحوه پیاده‌سازی سیاست جداسازی منابع (Resource Isolation Policy) و چرایی اهمیت این مشخصه برای توسعه‌دهندگان مایکروسافت NET 11. و ASP.NET Core تحلیل شده است.

مقدمه
تصور کنید سرور شما درخواستی دریافت می‌کند که هدف آن تغییر رمز عبور کاربر یا انتقال یک سند حساس است. مرورگر، کوکی‌های احراز هویت را طبق معمول ارسال کرده‌است. اما آیا این درخواست نتیجه‌ی کلیک خود کاربر روی یک دکمه در برنامه شماست، یا یک اسکریپت مخرب در تگی در یک سایت دیگر آن را تحریک کرده است؟
تا پیش از این، پاسخ به این پرسش برای سرور دشوار بود. رویکردهای قبلی بیشتر بر محدودسازی رفتاری مرورگر تمرکز داشتند (مانند CORS یا سیاست‌های هدر امنیتی)؛ اما مشخصه Fetch Metadata تغییر الگویی را پیشنهاد می‌کند: اعطای زمینه (Context) شفاف به سرور تا خود در مورد پذیرش یا رد درخواست تصمیم بگیرد.

ویژگی حیاتی: هدرهای Fetch Metadata توسط مرورگر به صورت خودکار و سطح پایین (Low-level) تنظیم می‌شوند و به‌هیچ‌عنوان از طریق APIهای جاوااسکریپت (مانند fetch یا Axios) قابل تغییر یا دستکاری نیستند. بنابراین، اطلاعات دریافت شده در سمت سرور صددرصد قابل اعتماد (Trusted) هستند.

بررسی دقیق هدرهای چهارگانه Fetch Metadata
چهار هدر تعریف‌شده در این مشخصه، تصویر کاملی از منشأ و نیت درخواست به سرور ارائه می‌دهند:
[ HTTP Request Headers ]
 ├── Sec-Fetch-Dest : مقصد پاسخ (image, script, document, ...)
 ├── Sec-Fetch-Site : رابطه مبدأ و مقصد (same-origin, cross-site, ...)
 ├── Sec-Fetch-Mode : حالت درخواست (navigate, cors, no-cors, ...)
 └── Sec-Fetch-User : نقش مستقیم کاربر در شروع درخواست (?1)

هدرSec-Fetch-Dest(مقصد درخواست)
این هدر مشخص می‌کند که پاسخ درخواست قرار است در چه محلی یا برای چه عنصری در مرورگر استفاده شود.
  • document: درخواست ناشی از ناوبری سطح بالا (Top-level Navigation) است (مثل کلیک روی لینک یا وارد کردن URL در آدرس‌بار) و صفحه فعلی را جایگزین می‌کند.
  • empty: درخواست مقصد تجسمی در HTML ندارد. معمولاً توسط فراخوانی‌های fetch()، XMLHttpRequest یا WebSocket ایجاد می‌شود.
  • image: پاسخ به عنوان تصویر استفاده خواهد شد (تگ <img>، تصویر پس‌زمینه در CSS و...).
  • سایر مقادیر رایج: script ،style ،font ،iframe ،audio ،video ،worker.
کاربرد امنیتی: اگر سرور درخواستی برای یک فایل حساسی مانند json. یا js. دریافت کند اما هدر Sec-Fetch-Dest مقدار image داشته باشد، مشخص است که درخواستی غیرعادی (احتمالاً یک حمله) در جریان است و سرور می‌تواند بلافاصله آن را مسدود کند.

هدرSec-Fetch-Site(رابطه مبدأ و مقصد)
این هدر موقعیت جغرافیایی/دامنه‌ای درخواست‌کننده را نسبت به سرور مقصد توصیف می‌کند و یکی از ۴ مقدار زیر را می‌پذیرد:
  • same-origin: مبدأ و مقصد کاملاً یکسان هستند (پروتکل، دامنه، زیردامنه و پورت یکسان).
  • same-site: پروتکل و دامنه یکسان هستند، اما ممکن است زیردامنه یا پورت متفاوت باشد.
  • cross-site: مبدأ و مقصد از دو سایت کاملاً متفاوت هستند.
  • none: درخواست تعاملی نبوده و از صفحه‌ای دیگر شروع نشده است (مانند تایپ مستقیم URL یا باز کردن از Bookmark).

برای درک بهتر تفاوت same-origin و same-site مقایسه زیر را نسبت به مقصد [http://www.example.org](http://www.example.org) ببینید:

URL مبدأتوضیحاتSame-SiteSame-Origin
[http://www.example.org](http://www.example.org)آدرس کاملاً یکسان✅✅
[http://www.example.org:8080](http://www.example.org:8080)پورت متفاوت✅❌
[http://sub.example.org](http://sub.example.org)زیردامنه متفاوت✅❌
[https://www.example.org](https://www.example.org)پروتکل متفاوت (HTTPS)❌❌
[http://www.evil.org](http://www.evil.org)دامنه متفاوت❌❌

هدرSec-Fetch-Mode(حالت اجرای درخواست)
این هدر نحوه ساخت و رفتار مرورگر در قبال درخواست را مشخص می‌کند. درک این هدر مستلزم تمایز میان حالت‌های زیر است:
  • navigate: برای درخواست‌های ناوبری بین صفحات HTML استفاده می‌شود.
  • same-origin: درخواست‌های درون‌برنامه‌ای که نیاز به CORS ندارند.
  • cors: درخواست‌های Cross-Origin که با استاندارد CORS ارسال می‌شوند. پاسخ تنها در صورت وجود هدرهای Access-Control-Allow-Origin توسط جاوااسکریپت قابل خواندن است.
  • no-cors: درخواست‌های Cross-Origin ساده (مانند بارگذاری تصویر یا استایل). مرورگر اجازه خواندن پاسخ را به جاوااسکریپت نمی‌دهد (پاسخ Opaque یا کدر است).
  • websocket: درخواست برای برقراری ارتباط WebSocket.
نکته تکمیلی: هنگامی که مرورگر یک تگ img را بارگذاری می‌کند، درخواست در حالت no-cors ارسال می‌شود. سرور اگر بداند یک API حساس (مثلاً /api/delete-user) فقط باید از طریق JS و حالت cors فراخوانی شود، اما درخواستی با حالت no-cors برای آن بیاید، می‌تواند آن را فوراً رد کند.

هدرSec-Fetch-User(تعامل مستقیم کاربر)
این هدر بسیار ساده، اما کلیدی است. اگر درخواست به طور مستقیم با تعامل کاربر (مانند کلیک روی لینک یا ارسال فرم) تحریک شده باشد، مقدار آن برابر 1? خواهد بود. در غیر این صورت، این هدر کلاً ارسال نمی‌شود.

بررسی سناریوهای واقعی در مرورگر
برای مشاهده نحوه همکاری این ۴ هدر، سناریوی رفتاری زیر را در نظر بگیرید:
۱. ورود کاربر با تایپ آدرس سایت در مرورگر
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

۲. بارگذاری فایل CSS اختصاصی از همان سرور
Sec-Fetch-Dest: style
Sec-Fetch-Mode: same-origin
Sec-Fetch-Site: same-origin

۳. بارگذاری تصویر از روی CDN (دامنه‌ای متفاوت)
Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site

۴. ارسال درخواست AJAX توسط جاوااسکریپت به یک API ثالث
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

لایه دفاعی جدید: تعریف Resource Isolation Policy
حملات CSRF (Cross-Site Request Forgery) هنگامی رخ می‌دهند که یک سایت مخرب، مرورگر کاربر را مجبور به ارسال ناخواسته یک درخواست به سایت شما کند.
با کمک Fetch Metadata، می‌توانید یک سیاست جداسازی منابع (Resource Isolation Policy) در سرور پیاده‌سازی کنید. منطق پایه این دفاع به شرح زیر است:
[ ورود درخواست به سرور ]
        │
        ├── آیا Sec-Fetch-Site برابر same-origin یا same-site یا none است؟
        │     ├── بله ──> [ مجاز ]
        │     └── خیر ──> آیا یک ناوبری سطح بالا است؟ (Dest=document AND Mode=navigate AND Method=GET)
        │                   ├── بله ──> [ مجاز (کاربر روی لینک کلیک کرده) ]
        │                   └── خیر ──> [ مسدودسازی (درخواست Cross-Site غیرمجاز) ]

چشم‌انداز اکوسیستم دات‌نت: NET 11. و ASP.NET Core
تیم مایکروسافت در نسخه NET 11. مکانیزم محافظت در برابر CSRF را بر پایه هدرهای Fetch Metadata بازنویسی و بسیار ساده‌تر کرده است.
در روش‌های سنتی Anti-Forgery Token:
  • نیاز به رندر توکن در فرم‌های HTML و ارسال آن در هدرها وجود داشت.
  • مشکلات انقضای توکن یا چالش‌های Caching رخ می‌داد.
در NET 11.، با استفاده از میدل‌ورهای مبتنی بر Fetch Metadata، توسعه‌دهنده بدون نیاز به تزریق توکن در همه جا، می‌تواند درخواست‌های متقاطع (Cross-Site) غیرمجاز را در بالاترین لایه خط لوله (Pipeline) برنامه مسدود کند.

نمونه کد مفهومی (Middleware در ASP.NET Core)
کد زیر نحوه پیاده‌سازی یک Middleware ساده برای محافظت مبتنی بر Fetch Metadata را نشان می‌دهد:
public class FetchMetadataValidationMiddleware
{
    private readonly RequestDelegate _next;

    public FetchMetadataValidationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var request = context.Request;

        // اگر هدر وجود نداشته باشد (مرورگرهای بسیار قدیمی)، اجازه عبور می‌دهیم یا طبق سیاست برخورد می‌کنیم
        if (request.Headers.TryGetValue("Sec-Fetch-Site", out var siteValues))
        {
            var site = siteValues.ToString();

            // ۱. درخواست‌های درون‌برنامه‌ای یا آدرس‌بار همیشه مجاز هستند
            if (site is "same-origin" or "same-site" or "none")
            {
                await _next(context);
                return;
            }

            // ۲. درخواست‌های Cross-Site فقط در صورتی مجاز هستند که ناوبری ساده GET باشند
            var dest = request.Headers["Sec-Fetch-Dest"].ToString();
            var mode = request.Headers["Sec-Fetch-Mode"].ToString();

            bool isTopLevelNavigation = HttpMethods.IsGet(request.Method) 
                                     && dest == "document" 
                                     && mode == "navigate";

            if (!isTopLevelNavigation)
            {
                // مسدودسازی درخواست‌های مشکوک Cross-Site (مثل POST از سایت دیگر)
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                await context.Response.WriteAsync("Cross-Site Request Blocked by Fetch Metadata Policy.");
                return;
            }
        }

        await _next(context);
    }
}

نتیجه‌گیری
هدرهای Fetch Metadata چارچوبی ساده، دقیق و غیرقابل دستکاری را برای سنجش منشأ و نیت درخواست‌های HTTP فراهم می‌سازند. این هدرها مکمل مکانیزم‌های دفاعی قبلی مانند SameSite Cookies و CORS بوده و لایه‌ای امن‌تر و شفاف‌تر ایجاد می‌کنند. با نزدیک شدن به انتشار NET 11.، آگاهی از نحوه عملکرد هدرهای Sec-Fetch-* به توسعه‌دهندگان ASP.NET Core کمک می‌کند تا علاوه بر درک بهتر مکانیزم‌های داخلی فریم‌ورک، برنامه‌هایی امن‌تر و با معماری مدرن‌تر طراحی کنند.

نظرات

  • وحید نصیری در ۱۴۰۵/۰۵/۰۸ ۰۸:۳۱
    در .NET 11، فریم‌ورک ASP.NET Core تغییر بزرگی در نحوه مقابله با حملات CSRF (Cross-Site Request Forgery) ایجاد کرده است.

    تا پیش از این، روش استاندارد و اصلی، استفاده از توکن‌های ضد جعل (Anti-Forgery Tokens) بود؛ اما در .NET 11 یک میدل‌ور به صورت پیش‌فرض فعال شده که بدون نیاز به توکن و بر پایه هدرهای Fetch Metadata (به ویژه Sec-Fetch-Site و Origin) از برنامه محافظت می‌کند. در ادامه، نحوه پیاده‌سازی این سیستم در .NET 11 و مقایسه همه‌جانبه آن با روش سنتی توکن‌محور بررسی شده است.

    ۱. نحوه کارکرد سیستم جدید در .NET 11
    در برنامه‌هایی که با WebApplication.CreateBuilder ساخته می‌شوند، میدل‌ور محافظت خودکار CSRF به طور خودکار در خط لوله (Pipeline) قرار می‌گیرد. این سیستم نیازی به تولید، نگهداری یا ارسال توکن‌های مخفی در فرم‌ها ندارد.

    فرآیند ارزیابی درخواست‌ها (Evaluation Steps)
    وقتی درخواستی به سرور می‌رسد، میدل‌ور بر اساس الگوریتم زیر اعتبار آن را بررسی می‌کند:
    • متدهای امن (Safe Methods): درخواست‌های GET ،HEAD ،OPTIONS و TRACE همیشه مجاز هستند (طبق استاندارد RFC 9110).
    • درخواست‌های درون‌برنامه‌ای: اگر هدر Sec-Fetch-Site مقدار same-origin (ناوبری داخلی) یا none (ورود مستقیم از آدرس‌بار) داشته باشد، درخواست تایید می‌شود.
    • اعتبارسنجی با CORS: اگر درخواست دارای هدر Origin باشد و آن Origin در سیاست‌های CORS برنامه ثبت شده باشد، مجاز تلقی می‌شود.
    • رد درخواست‌های Cross-Site غیرمجاز: اگر Sec-Fetch-Site مقادیر cross-site یا same-site داشته باشد و مبدأ آن در CORS تایید نشده باشد، درخواست نامعتبر (Invalid) علامت‌گذاری می‌شود.
    • کلاینت‌های غیرمرورگری (Non-Browser): اگر هیچ‌یک از هدرهای Sec-Fetch-Site و Origin وجود نداشته باشند (مثل درخواست‌های Postman ،cURL یا اپلیکیشن‌های موبایل)، درخواست مجاز شناخته می‌شود (زیرا CSRF یک آسیب‌پذیری وابسته به مرورگر است).
    مفهوم Deferred Validation (اعتبارسنجی به‌تعویق‌افتاده):
    این میدل‌ور درخواست غیرمجاز را بلافاصله قطع نمیکند؛ بلکه یک نشانگر (Verdict) نامعتبر روی IAntiforgeryValidationFeature درخواست ثبت می‌کند. سپس هنگامی که اجزای پردازش فرم (مانند Razor Pages، کنترلرهای MVC، Blazor SSR یا Form Binding در Minimal API) قصد خواندن بدنه فرم را دارند، این نشانگر را چک کرده و پاسخ 400 Bad Request برمی‌گردانند.

    ۲. مقایسه جامع: Fetch Metadata در برابر Anti-Forgery Token

    ویژگی / محور مقایسهسیستم جدید (Fetch Metadata)سیستم سنتی (Anti-Forgery Token)
    مبنای امنیتهدرهای غیرقابل تغییر مرورگر (Sec-Fetch-Site, Origin)توکن‌های رمزنگاری‌شده (Synchronizer Token Pattern)
    نیاز به تغییر کد HTML❌ خیر (به هیچ Input مخفی یا هدری نیاز نیست)✅ بله (نیاز به یا هدر سفارشی)
    بار پردازشی سروربسیار سبک (صرفاً بررسی هدرهای متنی)سنگین‌تر (تولید، رمزنگاری و اعتبارسنجی توکن‌ها)
    وابستگی به Data Protection❌ ندارد✅ دارد (در Server Farm نیاز به کلیدهای مشترک دارد)
    مشکلات Caching / CDN❌ ندارد (پاسخ‌های HTML کاملاً استاتیک باقی می‌مانند)⚠️ دارد (تولید توکن یکتا مانع Caching صفحات می‌شود)
    پشتیبانی از مرورگرهاتمام مرورگرهای مدرن (Chrome, Firefox, Safari, Edge)تمام مرورگرها (حتی مرورگرهای قدیمی بدون پشتیبانی از Fetch Metadata)
    کلاینت‌های غیر مرورگربه صورت خودکار bypass می‌شوندنیاز به استثنا کردن یا مدیریت توکن دارند

    ۳. نحوه پیاده‌سازی و پیکربندی در .NET 11
    حالت پایه (پیش‌فرض)
    در .NET 11، اگر از الگوی استاندارد استفاده کنید، این سیستم بدون هیچ کد اضافی فعال است:
    var builder = WebApplication.CreateBuilder(args);
    
    // میدل‌ورهای MVC یا Razor Pages یا Minimal API
    builder.Services.AddControllersWithViews();
    
    var app = builder.Build();
    
    app.UseRouting();
    app.UseAuthorization();
    
    // محافظت CSRF مبتنی بر Fetch Metadata به صورت خودکار فعال است
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    app.Run();

    سناریوی ۱: مجاز کردن مبداهای متقاطع با CORS
    اگر یک وب‌سایت دیگر (مثلاً [https://trusted-partner.com](https://trusted-partner.com)) قرار است فرم‌هایی را به API شما ارسال کند، می‌توانید آن را از طریق CORS مجاز کنید:
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("AllowSpecificOrigin", policy =>
        {
            policy.WithOrigins("https://trusted-partner.com")
                  .AllowAnyMethod()
                  .AllowAnyHeader();
        });
    });
    
    // اعمال سیاست روی انتهای مورد نظر
    app.MapPost("/submit-partner-form", (MyFormModel data) => Results.Ok())
       .RequireCors("AllowSpecificOrigin");

    سناریوی ۲: غیرفعال کردن محافظت روی یک Endpoint خاص
    اگر Endpoint خاصی نیازی به این محافظت ندارد (مثلاً یک Webhook عمومی یا API غیر مرورگری):
    // در Minimal API
    app.MapPost("/api/webhook", (WebhookData data) => Results.Ok())
       .DisableAntiforgery();
    
    // در کنترلرهای MVC / Razor Pages
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public IActionResult WebhookReceiver([FromBody] WebhookData data)
    {
        return Ok();
    }

    سناریوی ۳: همزیستی با سیستم توکن‌محور (Coexistence)
    این دو سیستم مانعه‌الجمع نیستند. اگر برنامه‌ای قدیمی‌تر دارید که نیازمند اعتبارسنجی توکن لایه سخت‌گیرانه‌تر است، می‌توانید هر دو را هم‌زمان داشته باشید:
    // فعال‌سازی خدمات توکن سنتی در صورت نیاز
    builder.Services.AddAntiforgery(options =>
    {
        options.HeaderName = "X-XSRF-TOKEN";
    });
    
    // استفاده از ویژگی سنتی روی اکشن‌های خاص
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult LegacyProtectedAction()
    {
        return Ok();
    }

    ۴. جمع‌بندی و توصیه پیاده‌سازی
    • برای برنامه‌های جدید در .NET 11: به محافظت خودکار مبتنی بر Fetch Metadata تکیه کنید. نیاز به اضافه کردن Tag Helperهای مربوط به Anti-Forgery یا مدیریت توکن در کلاینت‌های AJAX برطرف شده است.
    • برنامه‌های در حال مهاجرت (Migration): سیستم جدید با کدهای قبلی تداخلی ندارد. می‌توانید به تدریج کدهای توکن‌محور قدیمی را حذف کرده و به مدل ساده‌تر بدون توکن در .NET 11 سوئیچ کنید.
    • برای APIهای صرفاً JSON: از آنجا که حملات CSRF عمدتا متوجه فرم‌های HTML و Cookieها هستند، endpoints منطبق با JSON نیازی به اقدام خاصی ندارند، اما سیستم جدید همچنان نشانگرهای مربوطه را بدون اختلال ثبت می‌کند.