اعتبارسنجی خودکار Anti-forgery tokens در Asp.Net Core 3.1

Anti-forgery tokens یک مکانیزم امنیتی برای دفاع در برابر حملات و درخواست های جعلی از طریق سایت است که به حملات CSRF معروف است . 

ابتدا روال معمولی این محافظت را در هسته Asp.Net Core بررسی میکنیم . 

وقتی فرم را به کاربر ارسال میکنید یک قسمت مخفی اضافی ، اضافه میکند که نیمی از نشانه های رمزنگاری است علاوه بر این یک Cookie به نیمه دیگر Token تنظیم می شود و هنگامی که فرم به سرور ارسال می شود اطمینان حاصل می شود که فقط درخواست های معتبر ارائه می شود

در Asp.Net Core هنگام استفاده از Tag Helper مربوط به *-asp  به طور خودکار Token ها اضافه می شوند . 

<form asp-controller="Product" asp-action="Create" method="post">
   
</form>

این نشانه گذاری مشابه زیر ایجاد می شود که میتوانید ورودی مخفی با نشان anti-forgery token را مشاهده کنید .

<form method="post" action="/Product/Create">
  <input name="__RequestVerificationToken" type="hidden" 
  value="CfDJ8NrAkSldwD9CpLR...LongValueHere!" />
</form>

نکته :
در Asp.Net Core 2.0 از Tag Helper مربوط به *-asp استفاده کنید یا نه در هر صورت Token مربوط به  anti-forgery token را به تمامی فرم های شما اضافه میکند .


افزودن فیلد فرم در واقع تنها بخشی از شرط مورد نیاز است و همچنین باید بررسی معتبر بودن Token ها در سمت سرور هم بررسی شود و میتوانید این کار را با تزیین کننده (decorating) ویژگی [ValidateAntiForgeryToken] در بالای اکشن و یا کنترلر خود انجام دهید . و برای محافظت صحیح از برنامه خود باید آن را به تمام اکشن های Post خود اضافه کنید .

public class ProductController
{
  [HttpPost]
  [ValidateAntiForgeryToken]
  public IActionResult Create()
  {
    return View();
  }
}

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

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

مفهوم Global Filter برای هر عملی در برنامه اعمال می شود و متاسفانه روی تمامی اکشن های ما از جمله Get این اتفاق می افتد .

برای این کار 2 راه کار وجود دارد :

1 – ساخت یک Middlware مربوط به Antiforgery Tokens

using System.Threading.Tasks;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;

public class ValidateAntiForgeryTokenMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IAntiforgery _antiforgery;

    public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
    {
        _next = next;
        _antiforgery = antiforgery;
    }

    public async Task Invoke(HttpContext context)
    {
        if (HttpMethods.IsPost(context.Request.Method))
        {
            await _antiforgery.ValidateRequestAsync(context);
        }

        await _next(context);
    }
}

در اینجا بررسی میکنیم که آیا درخواست HTTP فعلی یک درخواست POST است یا خیر و اگر درست باشد antiforgery token را ارسال میکنیم . 

اگر درخواست شامل antiforgery token معتبر نباشد ValidateRequestAsync یک AntiforgeryValidationException رو پرتاب میکند در این حالت _Next فرخوانی نمی شود و بقیه خط لوله (pipeline) درخواست اجرا نخواهد شد و پس از آن خطایی برای نمایش کاربر وجود دارد . 

در آخر برای اضافه کردن این Middlware به صورت زیر عمل میکنیم :

public void Configure(IApplicationBuilder app)
{
    app.UseAntiforgeryTokens();
}

2 – استفاده از ویژگی ای به نام [AutoValidateAntiForgeryToken]

خوشبختانه در Asp.Net Core یک ویژگی به نام [AutoValidateAntiForgeryToken] این Attribute را فراهم میکند و این بار در خواست های Get را نادیده می گیرد چیزی که مدنظر ما بود . افزودن این ویژگی بسیار ساده است . فقط کافی است هنگام صدا زدن ()AddMVC آن را به مجموعه global filter ها در Startup اضافه کنید

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    services.AddMvc(options =>
    {
        options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
    });
  }
}

کار تمام است و دیگر بدون تزیین کننده (decorate) تمامی اکشن ها به صورت خودکار محافظت می شود .