1

I have an MVC site with an embedded angular client and I've recently implemented an anti forgery XSRF token as a security measure.

I have set it up in Startup.cs as follows:

services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

app.Use(next => context =>
        {
            if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase))
            {
                // We can send the request token as a JavaScript-readable cookie, and Angular will use it by default.
                var tokens = antiforgery.GetAndStoreTokens(context);
                context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                    new CookieOptions() { HttpOnly = false });
            }

            return next(context);
        });

And I've implemented it within my angular front-end like so:

{ provide: XSRFStrategy, useFactory: xsrfFactory}

export function xsrfFactory(): CookieXSRFStrategy {
return new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN');
}

And protecting my controllers like:

[Authorize] //Validation of AzureAD Bearer Token.
[ValidateAntiForgeryToken]
public class UserController : Controller

It is intended that the X-XSRF-TOKEN header be validated with any call to my API, and this works successfully for all calls in the original session. However, my app uses Adal to log the user in, and after the redirect from a successful login, this validation step fails and I receive a 400 from my API for any subsequent calls.

The original X-XSRF-TOKEN header is still sent with all outgoing requests from my angular client after the login so I suspect it must be that my server side no longer has the token to validate against, or my server has generated a new one and my client doesn't retrieve it. But for whatever reason it breaks down and it's very hard to debug without creating some custom filter so I can see what's going on inside it.

Is there a way to reset this token after a client side redirect so that both my server and client share common knowledge of it again? Or should I be generating the token in my Index.html for example?

EDIT

Edited controller decoration above for missing [Authorize] attribute.

So my controller is protected by a step validating the AzureAD Bearer token as well as the Anti-Forgery validation. Removing the AzureAD Validation as a test did not resolve the issue, oddly.

Error on failing API calls displays in output after Adal login as:

The provided anti-forgery token was meant for a different claims-based user than the current user.

JonnyKnottsvill
  • 1,123
  • 2
  • 16
  • 39
  • When you authenticate the adal, did you using the pop-up page? If yes, is it helpful to set the `popUp` to false? – Fei Xue Jul 05 '17 at 10:07
  • @FeiXue-MSFT No it is not a pop-up, I navigate away to `login.microsoft.com/xxx` and provide a redirectUrl for successful logins. Please see my edit for an error found in output when the API calls fail. I've also included now that I first validate the users bearer token using the AzureAD Authorize pipeline. I missed that previously. – JonnyKnottsvill Jul 05 '17 at 10:17

2 Answers2

0

Based on my understanding, you were protecting the controller using token. For this issue is expected, you can refer the progress of validate the anti-XSRF tokens from below(refer this link):

To validate the incoming anti-XSRF tokens, the developer includes a ValidateAntiForgeryToken attribute on her MVC action or controller, or she calls @AntiForgery.Validate() from her Razor page. The runtime will perform the following steps:

  1. The incoming session token and field token are read and the anti-XSRF token extracted from each. The anti-XSRF tokens must be identical per step (2) in the generation routine.
  2. If the current user is authenticated, her username is compared with the username stored in the field token. The usernames must match.
  3. If an IAntiForgeryAdditionalDataProvider is configured, the runtime calls its ValidateAdditionalData method. The method must return the Boolean value true.

Since you were developing the SPA application with back-end web API, when the request to the web API, it will always issue the anti-XSRF token with no identity. And when you send the request to the back-end with anti-XSRF and Azure AD token, this time the web API already authenticate the request via the Azure AD token. And it will always return false when checking anti-XSRF token to match the identity information.

In this scenario, if the back-end only using the bear token authentication and store the token with session storage, there is no need to enable XSRF prevention since others is not able to steal the token and forge the request.

If your back-end also support the cookie authentication or basic auth, NTLM etc, you can disable the identity checking by adding the following to your Application_Start method: AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.(refer this link)

More detail about XSRF/CSRF abouth oauth and web API, you can refer the threads below:

How does ValidateAntiForgeryToken fit with Web APIs that can be accessed via web or native app?

AntiForgeryToken does not work well with OAuth via WebAPI

Community
  • 1
  • 1
Fei Xue
  • 14,369
  • 1
  • 19
  • 27
0

Try replacing [ValidateAntiForgeryToken] with [AutoValidateAntiforgeryToken]

https://github.com/aspnet/Antiforgery/blob/dev/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenGenerator.cs

MattM2017
  • 11
  • 3