Preventing CSRF Attacks In ASP.NET Core 2.0

Problem

How to prevent Cross-Site Request Forgery attacks in ASP.NET Core.

Solution

Create an empty project and update Startup to add middleware and services for MVC,

Create a model and service,

Note - The implementation of the service doesn’t matter here but it can be getting data from EF etc. In the sample, I just stored data in-memory.

Add a Controller.

Add an Index View.

Add a Create view.

Run and browse to Create view and observe its source.

  1. <strong>Create</strong>  
  2.    
  3. <form method="post" action="/Home/Save">  
  4.     <label for="Title">Title</label>  
  5.     <input type="text" id="Title" name="Title" value="" /> <br />  
  6.    
  7.     <br />  
  8.     <button type="submit">Save</button><br />  
  9.     <input name="__RequestVerificationToken" type="hidden" value="CfDJ8N-xGVhsz-FFuPUED-HLkPE1W4kY7t4IBowqElti5j6zVsXpONu4D8nZ6wdM50tq-X-Y-hA-gPBiXcxzpBmhgxGmzcJSX6Aopc239-js0cPwQv0jZK-l5pY8Z9EZHFC_LCdp2VO3pCp1PKy8D_-T_C8" />  
  10. </form> 
Also, note the cookie added for anti-forgery.

Add a new entry and observe the request in fiddler.

Discussion

OWASP 2013 classifies Cross-Site Request Forgery (CSRF) as one of the top 10 risks and it is present if an attacker can force the victim's browser to send a forged request to the web application which considers it a legitimate request.

ASP.NET Core provides an easy to use mechanism to prevent such attacks by

  1. Creating a cookie with an encrypted token.
  2. Emitting a hidden form element (__RequestVerificationToken) with an encrypted token.

The cookie and form field will be sent to server on subsequent requests, as observed in the above fiddler screenshot. Server will reject the request if any of the two (cookie or form field) is missing, e.g. - excluding the form field returns a 400 (Bad Request).

Server will also throw an exception if any of the two (cookie or form field) is modified, e.g. - below, I changed the value of form field.

How it works

In order to add the hidden tokens, we just need to use the form tag and apply [ValidateAntiForgeryToken] attribute to our controller action. Yes, that’s it.

You could also apply the [AutoValidateAntiforgeryToken] attribute on your controller to enable the forgery token validation for all the unsafe actions (e.g. POST and PUT) on your controller

If you want to apply validation for all the controllers in your application, you could add a global filter when configuring MVC services

With validation enabled globally, you could disable for certain actions using the [IgnoreAntiForgeryToken] attribute

This last option is the safest option and would be my preference i.e. apply validation globally and ignore as needed.

Note - Without the token validation attribute or filter, hidden tokens inside the form and cookie are not going to stop the CSRF attacks.

Source Code

GitHub