Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AntiForgeryToken Expiration Blank Page

I'm using IdentityServer4 with ASP.NET Core 2.2. On the Post Login method I have applied the ValidateAntiForgeryToken. Generally after 20 minutes to 2 hours of sitting on the login page and then attempting to login it produces a blank page.

If you look at Postman Console you get a 400 Bad Request message. I then set the Cookie Expiration on the AntiForgery options to 90 days. I was able to allow the page to sit for up to 6 hours and still login. However, after around 8 hours (overnight), I received the blank page again after attempting to login.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login
services.AddAntiforgery(options =>
{
    options.Cookie.Expiration = TimeSpan.FromDays(90);
});

I expect to be able to sit on the login page for 90 days which is the duration of the cookie but that doesn't work. How do I get the cookie for the AntiforgeryToken to last the entire 90 days or whatever time I set it to and not timeout or expire? Is there a way to catch this error and redirect the user back to the login method?

like image 724
Rodney Bates Avatar asked May 24 '19 14:05

Rodney Bates


People also ask

How long is AntiForgeryToken valid?

This cookie is used to store the antiforgery token value in the client side, so clients can read it and sends the value as the HTTP header. Default cookie name is XSRF-TOKEN , expiration time is 10 years (yes, ten years!

What does HTML AntiForgeryToken () do?

AntiForgeryToken()Generates a hidden form field (anti-forgery token) that is validated when the form is submitted.

Is the Antiforgery token could not be decrypted?

The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.


1 Answers

Update '2021

Since ASP.Net Core 3.0 MS decided to make ValidateAntiforgeryTokenAuthorizationFilter internal. Now we have to copy-paste their code, to be able to derive. But most likely we don't need to. To just change the resulting behavior all we need is to test the context for the IAntiforgeryValidationFailedResult and proceed accordantly, as described in this example.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc.Filters;

namespace BasicWebSite.Filters
{
    public class RedirectAntiforgeryValidationFailedResultFilter : IAlwaysRunResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            if (context.Result is IAntiforgeryValidationFailedResult result)
            {
                context.Result = 
                    new RedirectResult("http://example.com/antiforgery-redirect");
            }
        }

        public void OnResultExecuted(ResultExecutedContext context)
        { }
    }
}

Then within the controller:

// POST: /Antiforgery/LoginWithRedirectResultFilter
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[TypeFilter(typeof(RedirectAntiforgeryValidationFailedResultFilter))]
public string LoginWithRedirectResultFilter(LoginViewModel model)
{
    return "Ok";
}

The original answer covering .net core 2.2

Yet another implementation using the default one including all prechecks, logging etc. And it's still an AuthorizationFilter, so that prevents any further action execution. The only difference is that it triggers HttpGet to the same url instead of the default 400 response, a kind of the Post/Redirect/Get pattern implementation.

public class AnotherAntiForgeryTokenAttribute : TypeFilterAttribute
{
    public AnotherAntiForgeryTokenAttribute() : base(typeof(AnotherAntiforgeryFilter))
    {
    }
}


public class AnotherAntiforgeryFilter:ValidateAntiforgeryTokenAuthorizationFilter,
    IAsyncAuthorizationFilter
{
    public AnotherAntiforgeryFilter(IAntiforgery a, ILoggerFactory l) : base(a, l)
    {
    }

    async Task IAsyncAuthorizationFilter.OnAuthorizationAsync(
        AuthorizationFilterContext ctx)
    {
        await base.OnAuthorizationAsync(ctx);

        if (ctx.Result is IAntiforgeryValidationFailedResult)
        {
            // the next four rows are optional, just illustrating a way
            // to save some sensitive data such as initial query
            // the form has to support that
            var request = ctx.HttpContext.Request;
            var url = request.Path.ToUriComponent();
            if (request.Form?["ReturnUrl"].Count > 0)
                url = $"{url}?ReturnUrl={Uri.EscapeDataString(request.Form?["ReturnUrl"])}";

            // and the following is the only real customization
            ctx.Result = new LocalRedirectResult(url);
        }
    }
}
like image 191
d_f Avatar answered Sep 21 '22 05:09

d_f