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
- Using Angular in an ASP.NET Core View with Webpack
- Secure ASP.NET Core MVC with Angular using IdentityServer4 OpenID Connect Hybrid Flow
- Anti-Forgery Validation with ASP.NET Core MVC and Angular
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); }
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
http://www.fiyazhasan.me/angularjs-anti-forgery-with-asp-net-core/
http://www.dotnetcurry.com/aspnet/1343/aspnet-core-csrf-antiforgery-token
https://en.wikipedia.org/wiki/Cross-site_request_forgery
https://stormpath.com/blog/angular-xsrf
