doc/WebSite/XSRF-CSRF-Protection.md
"Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated" (OWASP).
It's also briefly described here where it explains how to implement it into ASP.NET Web API.
ABP framework simplifies and automates CSRF protection as much as possible. The startup templates come with this pre-configured and it works out-of-the-box. In this document, we will explain how it's integrated into the ASP.NET platforms and how it works.
You don't normally need to protect the the GET, HEAD, OPTIONS and TRACE action HTTP verbs since they normally are side-effect free (they don't change the database). While ABP assumes this and implements Anti Forgery protection for only the POST, PUT, PATCH and DELETE verbs, you can change this behavior using the attributes defined in this document.
CSRF is a type of attack that is a problem for browsers because a browser sends all cookies (including auth cookies) in all requests, including cross-domain requests. This is not a problem for non-browser clients, like mobile applications. The ABP framework understands the difference and automatically skips anti-forgery validation for non- browser clients.
ASP.NET MVC has its own built-in AntiForgery system, but there are a few weaknesses:
ABP does following things to overcome these problems:
In this way, CSRF protection works almost seamlessly.
The startup templates already integrate the CSRF protections out-of-the-box. If you need to manually add it to your project (maybe you have a legacy project), follow this guide.
We need to add the following code in our Layout view:
@{
SetAntiForgeryCookie();
}
All pages that use this layout will include it. This method is defined in the base ABP view class. It creates and sets the appropriate token cookies and makes JavaScript do the side-work. If you have more than one layout, add this to all of them.
That's all we have to do for ASP.NET MVC applications. All AJAX requests will be protected automatically, but we should still use the @Html.AntiForgeryToken() HTML helper for our HTML forms which are not posted via AJAX. There is no need to add the ValidateAbpAntiForgeryToken attribute for the corresponding action.
XSRF protection is enabled by default. You can disable or configure it in your module's PreInitialize method. Example:
Configuration.Modules.AbpWeb().AntiForgery.IsEnabled = false;
You can also configure token and cookie names using Configuration.Modules.AbpWebCommon().AntiForgery object.
The ASP.NET Web API does not include an anti-forgery mechanism. However, ASP.NET Boilerplate provides the infrastructure to add automated CSRF protection for ASP.NET Web API Controllers.
If you are using the Web API inside an MVC project, no additional configuration is needed. Even if you are self-hosting your Web API layer in another process, no configuration is needed as long as you are making AJAX requests from a configured MVC application.
If your clients are different kinds of applications (say, an independent Angular application which can not use the SetAntiForgeryCookie() method as described above), then you should provide a way of setting the anti- forgery token cookie. One possible way of doing this is to create an api controller like the following:
using System.Net.Http;
using Abp.Web.Security.AntiForgery;
using Abp.WebApi.Controllers;
namespace AngularForgeryDemo.Controllers
{
public class AntiForgeryController : AbpApiController
{
private readonly IAbpAntiForgeryManager _antiForgeryManager;
public AntiForgeryController(IAbpAntiForgeryManager antiForgeryManager)
{
_antiForgeryManager = antiForgeryManager;
}
public HttpResponseMessage GetTokenCookie()
{
var response = new HttpResponseMessage();
_antiForgeryManager.SetCookie(response.Headers);
return response;
}
}
}
You can then call this action from the client to set the cookie.
ASP.NET Core MVC has a better Anti Forgery mechanism compared to previous versions (ASP.NET MVC 5.x):
ABP adds the following features:
The startup templates are already integrated to use CSRF protections out-of-the-box. If you need to manually add it to your project (maybe you created your project before we added it), follow this guide.
First, we must add the AutoValidateAntiforgeryTokenAttribute to the global filters while adding MVC in the ConfigureServices method of the Startup class:
services.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
This way, all MVC actions (except GET, HEAD, OPTIONS and TRACE as declared before) will be automatically validated for an anti-forgery token.
We must add the following code in our Layout view:
@using Abp.Web.Security.AntiForgery
@inject IAbpAntiForgeryManager AbpAntiForgeryManager
@{
AbpAntiForgeryManager.SetCookie(Context);
}
All the pages that use this layout will include it. It creates and sets the appropriate token cookies and makes JavaScript do all the work. If you have more than one layout, add this to all of them.
That's all we must do for ASP.NET Core MVC applications. All AJAX requests will work automatically. For non-ajax form submits, ASP.NET Core automatically adds an anti-forgery token field if you use one of asp-* tags in your form. So there's normally no need to use @Html.AntiForgeryToken().
Note: If you host your application in multiple instances and use redis, you should also use redis for antiforgery token.
Microsoft.AspNetCore.DataProtection.StackExchangeRedis nuget package to your Web project.Startup.cspublic void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToStackExchangeRedis(
ConnectionMultiplexer.Connect(_appConfiguration["Abp:RedisCache:ConnectionString"])
, "DataProtection-Keys"
);
...
}
The anti-forgery token must be provided in the request header for all AJAX requests, as we declared above. We will see how it's done here.
The abp.jquery.js script defines an AJAX interceptor which adds the anti-forgery token to the request header for every request. It gets the token from the abp.security.antiForgery.getToken() JavaScript function.
AngularJS automatically adds the anti-forgery token to all AJAX requests. See the Cross Site Request Forgery (XSRF) Protection section in the AngularJS $http document. ABP uses the same cookie and header names by default. So, Angular integration works out of the box.
If you are using any other library for AJAX requests, you have three options:
Since all libraries use JavaScript's native AJAX object, XMLHttpRequest, you can define a simple interceptor to add the token to the header:
(function (send) {
XMLHttpRequest.prototype.send = function (data) {
this.setRequestHeader(abp.security.antiForgery.tokenHeaderName, abp.security.antiForgery.getToken());
return send.call(this, data);
};
})(XMLHttpRequest.prototype.send);
A good library provides interception points (like jQuery and AngularJS), so follow your vendor's documentation to learn how to intercept requests and manipulate headers.
As a final option, you can use the abp.security.antiForgery.getToken() method to get the token and add it to the request header manually for every request. You probably do not need this and can solve this problem by using the methods described above.
You may wonder "How does ABP handle this?". Actually, we use the same mechanism described in the AngularJS documentation mentioned before. ABP stores the token into a cookie (as described above) and sets the request headers using that cookie. For validating it, it also integrates well into the ASP.NET MVC, Web API and Core frameworks.