Anti-Forgery Validation with ASP.NET Core MVC and Angular

This article shows how API requests from an Angular SPA inside an ASP.NET Core MVC application can be protected against XSRF by adding an anti-forgery cookie. This is required, if using Angular, when using cookies to persist the auth token.

Code: https://github.com/damienbod/AspNetCoreMvcAngular

Blogs in this Series

2020-06-27 Updated to ASP.NET Core 3.1, IdentityServer4 4.0.0 Angular 10.0.0
2019-08-27 Updated to ASP.NET Core 3.0, Angular 8.2.3
2018-06-16 Updated to ASP.NET Core 2.1, Angular 6.0.5
2017-09-22 Updated to ASP.NET Core 2.0, Angular 4.4.3

Cross Site Request Forgery

XSRF is an attack where a hacker makes malicious requests to a web app, when the user of the website is already authenticated. This can happen when a website uses cookies to persist the token of an trusted website, user. A pure SPA should not use cookies to as it is hard to protect against this. With a server side rendered application, like ASP.NET Core MVC, anti-forgery cookies can be used to protect against this, which makes it safer, when using cookies.

Angular automatically adds the X-XSRF-TOKEN HTTP Header with the anti-forgery cookie value for each request if the XSRF-TOKEN cookie is present. ASP.NET Core needs to know, that it must use this to validate the request. This can be added to the ConfigureServices method in the Startup class.

public void ConfigureServices(IServiceCollection services)
{
	...
	services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
	services.AddMvc();
}

The XSRF-TOKEN cookie is added to the response of the HTTP request. The cookie is a secure cookie so this is only sent with HTTPS and not HTTP. All HTTP (Not HTTPS) requests will fail and return a 400 response. The cookie is created and added each time a new server url is called, but not for an API call.

app.Use(async (context, next) =>
{
	string path = context.Request.Path.Value;
	if (path != null && !path.ToLower().Contains("/api"))
	{
		// XSRF-TOKEN used by angular in the $http if provided
		var tokens = antiforgery.GetAndStoreTokens(context);
		context.Response.Cookies.Append("XSRF-TOKEN", 
		  tokens.RequestToken, new CookieOptions { 
		    HttpOnly = false, 
		    Secure = true 
		  }
		);
	}

	...

	await next();
});

The API uses the ValidateAntiForgeryToken attribute to check if the request contains the correct value for the XSRF-TOKEN cookie. If this is incorrect, or not sent, the request is rejected with a 400 response. The attribute is required when data is changed. HTTP GET requests should not require this attribute.

[HttpPut]
[ValidateAntiForgeryToken]
[Route("{id:int}")]
public IActionResult Update(int id, [FromBody]Thing thing)
{
	...

	return Ok(updatedThing);
}

In Angular you need to make sure that the anti-forgery token is sent in the x-xsrf-token header.

This can be done by adding the token to a hidden field and using this in the headers of the request.

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<input type="hidden" id="__RequestVerificationToken"
       name="__RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

Angular can then use this:

private setHeaders() {
        this.headers = new HttpHeaders();
        this.headers = this.headers.set('Content-Type', 'application/json');
        this.headers = this.headers.set('Accept', 'application/json');
        const token: any = document.getElementById('__RequestVerificationToken');
        this.headers = this.headers.set('X-XSRF-TOKEN', token.value);
        console.log(token.value);
}

You can check the cookies in the chrome browser.

Or in Firefox using Firebug (Cookies Tab).

Links:

https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery

https://stackoverflow.com/questions/46040922/angular4-httpclient-csrf-does-not-send-x-xsrf-token

http://www.fiyazhasan.me/angularjs-anti-forgery-with-asp-net-core/

http://www.dotnetcurry.com/aspnet/1343/aspnet-core-csrf-antiforgery-token

http://stackoverflow.com/questions/43312973/how-to-implement-x-xsrf-token-with-angular2-app-and-net-core-app/43313402

https://en.wikipedia.org/wiki/Cross-site_request_forgery

https://stormpath.com/blog/angular-xsrf

11 comments

  1. […] Anti-Forgery Validation with ASP.NET Core MVC and Angular (Damien Bowden) […]

  2. Mike · · Reply

    Hi Damien, thanks so much for this! I always thought the ‘Implicit Flow’ was the correct pattern for an Angular app accessing APIs from an MVC backend. Are you recommending that a Hybrid Flow is “better” / “more appropriate” in a setup exactly like yours? (ie. where an Angular SPA is inside an ASP.NET Core MVC application and presented as an MVC View). I guess I haven’t wrapped my head around ‘when’ to use the Hybrid Flow.

    1. Hi Mike, thanks,

      Implicit Flow is the correct flow for Angular apps accessing APIs. This is an MVC app with Angular in the view. Because it uses server rendered views, the extra protection can be added to protect against XSRF etc. I believe this setup to be protected.

      SPA Angular with API => Implicit Flow

      MVC with angular in the View => undecided which is better, must think about this and compare the safety concerns.

      Greetings Damien

  3. astegmaier · · Reply

    Can you help me understand more of the reasoning behind the statement “HTTP GET requests should not require this statement [i.e. the ValidateAntiForgeryToken attribute]”? If you’re talking about the GET endpoints that provide the MVC view that contains the Angular page, that makes sense to me (the token has to be provided at some point before it can be checked). But I’m confused about GET API calls–why wouldn’t you want to / need to validate the AntiForgeryToken on those?

    1. I was just refering that HTTP GET requests should not be changing data on the server, so that the GET request does not need to be validated. That’s all. But your also correct, if the GET returns sensitive data, the cookie should be validated.

  4. […] via Anti-Forgery Validation with ASP.NET Core MVC and Angular — Software Engineering […]

  5. Hi Mike, thanks,
    Implicit Flow is the correct flow for Angular apps accessing APIs. This is an MVC app with Angular in the view. But I’m confused about GET API calls–why wouldn’t you want to / need to validate the AntiForgeryToken on those?

  6. How is the .AspNetCore.Antiforgery cookie used in this regard? ie the XSRF cookie is returned i app code and the Antiforgery cookie is issued under the hood but is the ValidateAntiForgeryToken checking for the existence of the X-XSRF-HEADER comparing it to the XSRF cookie or the .AspNetCore.Antiforgery cookie?

      1. Hi Jonathan, cool, thanks for the link

        Greetings Damien

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.