Search code examples
asp.net-coreblazor-webassembly.net-8.0antiforgerytoken

In .Net 8 with Client (WebAssembly) , Sever (AspNetCore hosted) and Shared project structure can't validate Antiforgey token


In my Sever Program.cs

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

builder.Services.AddAntiforgery();

app.UseRouting();
app.UseAntiforgery(); // Added this line
app.MapControllers();
///
///
app.Run();

When the client initialized for the first time or make the first API call (GET) to the server the cookies(antiforgery token) is never set why ?

To get around When the app first start I make an API call (GET) that set the cookie manually.

 var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });

Surprisingly, this now set the "XSRF-TOKEN" cookies along with default ".AspNetCore.Antiforgery._F6fq8lpsLA" but when I make a second POST API request(CreateOrUpdateUserAsync) the server always throws Bad Request.

    [HttpPost, Route("{userId:Guid}")]
    public async Task CreateOrUpdateUserAsync(Guid userId, [FromBody] UserUpdateModel updateModel, CancellationToken cancellationToken)
    {
       //do some database operation
    }

The request header for cookies is set with both "XSRF-TOKEN" and ".AspNetCore.Antiforgery._F6fq8lpsLA"

Looks like the antiforgery is not set up properly. Can I please get some guidance on what I am missing. I am using HTTPS for my localhost.

thanks

The antiforgery token should be set when the app load and on each subsequent call the antiforgey token should automatically be attached in the the request header as cookies. The server should validate it with success if it was generated from the server other throw errors


Solution

  • When the client initialized for the first time or make the first API call (GET) to the server the cookies (antiforgery token) is never set why?

    You can use the middleware to generate anti-forgery tokens. You can refer to this document . This way, when the client is initialized for the first time, the cookie (anti-forgery token) can be set. enter image description here

    After testing your code, I reproduced your problem.

    My program.cs:

    using Microsoft.AspNetCore.Antiforgery;
    using Microsoft.AspNetCore.Mvc;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddControllersWithViews(options =>
    {
        options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
    });
    
    builder.Services.AddAntiforgery();
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    app.Run();
    

    My sample controller:

    using Microsoft.AspNetCore.Antiforgery;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApplication107.Controllers
    {
        public class AntiforgeryController : Controller
        {
            private readonly IAntiforgery _antiforgery;
    
            public AntiforgeryController(IAntiforgery antiforgery)
            {
                _antiforgery = antiforgery;
            }
    
            [HttpGet]
            public IActionResult GetToken()
            {
                var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
                Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
                    new CookieOptions { HttpOnly = false });
    
                return Ok(new { Message = "Antiforgery token set." });
            }
    
            [HttpPost]
         
            public IActionResult PostData( DataModel data)
            {
              
                return Ok(new { Message = "Data processed successfully." });
            }
        }
    
        public class DataModel
        {
            public string Data { get; set; }
        }
    }
    

    When I access the get method, the request is not intercepted: enter image description here

    The same situation also occurred to me:

    Surprisingly, this now set the "XSRF-TOKEN" cookies along with default ".AspNetCore.Antiforgery._F6fq8lpsLA" but when I make a second POST API request(CreateOrUpdateUserAsync) the server always throws Bad Request

    enter image description here

    enter image description here

    Reason: Because use the AutoValidateAntiforgeryTokenAttribute attribute, the attribute causes the POST operation to be protected by default, and it does not require a token to make a request using the HTTP GET method. You can refer to the document . The GetAndStoreTokens method generates an anti-forgery token for the current HTTP context, and the Response.Cookies.Append method is used to add a new Cookie to the HTTP response., "XSRF-TOKEN" is the name of this cookie, so the generated token is added to the cookie. To verify the anti-counterfeiting token, you need to read the token from the cookie when sending the request and include it in the request header, and then configure the ASP.NET Core anti-counterfeiting token service on the server side to verify the request header.

    The following is a code example :

    Configure the ASP.NET Core anti-counterfeiting token service on the server side to verify the request. Here I set the request header name of the anti-forgery token to TOKEN for verification:

    builder.Services.AddAntiforgery(options =>
    {
        options.HeaderName = "TOKEN";
        options.SuppressXFrameOptionsHeader = false;
    });
    

    Get the value of XSRF-TOKEN in the get method and add the name and value of the corresponding request header:

    enter image description here

    I can successfully access the post method enter image description here

    Therefore, it is necessary to check whether the token is read from the cookie and included in the request header when the client sends the request, and configure the ASP.NET Core anti-counterfeiting token service on the server to verify the request header.