January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Prevent Cross-Site Request Forgery In ASP.NET Core

If you worked with ASP.NET MVC applications before, you are probably aware of Cross-site request forgery (CSRF / XSRF) attacks. You might have also used anti-forgery token based approach to prevent them. ASP.NET Core uses a similar approach but there are a few differences that you should be aware of. To that end this article briefly discusses the CSRF attack and ASP.NET Core way to prevent them.

Although we won't discuss CSRF attacks in detail in this article, let's take a simplified scenario to understand them. If you know what CSRF is you can skip to the code level discussion.

Suppose you are logged in to a website. As a part of the login process the website has issued you an authentication token in the form of a cookie. So, your browser has this cookie with it. Now somehow you land on a malicious website. May be you clicked a hyperlink from an email or something similar. Now the malicious website cleverly issues requests (say POST requests) to the website you logged in earlier. This is perfectly possible because that's how web and HTML works. However, the malicious website attempts to tamper with the data by sending requests that may insert or delete data in the system. Since you are already authenticated with the website your requests might be successfully executed. This is certainly undesirable and should be prevented.

Luckily, ASP.NET Core provides us means to prevent such attacks. Let's see how.

Consider the following form tag helper

<form asp-action="Process" 
      asp-controller="Home"
      asp-antiforgery="true"
      method="post">
          
</form>

The form helper uses asp-action and asp-controller attributes to indicate that the form will be handled by the Process() action of the HomeController. The form tag helper also has asp-antiforgery attribute and its value is true. Setting this attribute to true emits a hidden form field containing the anti-forgery token. The following markup shows how this hidden field looks like in the browser's view source window:

As you can see the __RequestVerificationToken hidden form field has been added for you inside the form. This token needs to be validated inside your controller (more about that in a minute).

Actually adding asp-antiforgery attribute explicitly is not always necessary. If the form tag helper has its method attribute set to POST, ASP.NET Core automatically emits the verification token for you. Here is the example:

<form asp-action="Process" 
      asp-controller="Home"
      method="post">
          
</form>

And this is what the browser receives:

Same as before. Isn't it?

Note that if form's method is GET then the anti-forgery token is not emitted.

<form asp-action="Process" 
      asp-controller="Home"
      method="get">
          
</form>

And here is the output this time:

Also note that you can set asp-antiforgery attribute to false to disable the emission of the verification token.

<form asp-action="Process" 
      asp-controller="Home"
      asp-antiforgery="false"
      method="post">
          
</form>

And the following output proves that it is indeed disabled.

Ok. So far so good. We have completed half of the story. The remaining part is to actually verify this token in the controller. Our intentions is that an action under consideration - Process() in this case - should be executed only if the anti-forgery token is verified successfully. If this token is tampered with then the verification will fail and an exception is thrown.

To accomplish this task you can use three attributes :

  • [ValidateAntiForgeryToken]
  • [AutoValidateAntiforgeryToken]
  • [IgnoreAntiforgeryToken]

The [ValidateAntiForgeryToken] attribute ensures that an action is invoked only if the incoming request contains a valid anti-forgery token. This attribute validates all requests irrespective of the HTTP verb. You can apply this attribute to actions or controller. If applied to an action requests for that action are validated. If applied on controller requests for all of its actions are validated.

The [AutoValidateAntiforgeryToken] attribute is similar to the [ValidateAntiForgeryToken] attribute but doesn't validate GET, HEAD, OPTIONS, and TRACE requests. This attribute can also be applied to actions or controllers.

The [IgnoreAntiforgeryToken] attribute is used to skip validation for an action. This comes handy when you have applied [ValidateAntiForgeryToken] or [AutoValidateAntiforgeryToken] on the controller and want to skip validation just for a few actions.

Now, let's use these attributes in HomeController. The following code shows the Process() action with [ValidateAntiForgeryToken] or [AutoValidateAntiforgeryToken] applied.

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Process()
{
    return View();
}

[HttpPost]
[AutoValidateAntiforgeryToken]
public IActionResult Process()
{
    return View();
}

As you can see these attributes are being used at an action level. The following code shows how these attributes can be applied to a controller.

[ValidateAntiForgeryToken]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Process()
    {
        return View();
    }
}

And....

[AutoValidateAntiforgeryToken]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Process()
    {
        return View();
    }
}

Finally this is how you can use [IgnoreAntiforgeryToken] attribute.

[AutoValidateAntiforgeryToken]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [IgnoreAntiforgeryToken]
    public IActionResult Help()
    {
        return View();
    }
}

To read more about cross-site request forgery and its prevention you may read the official documentation here.

That's it for now! Keep coding!!


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 28 August 2017


Tags : ASP.NET ASP.NET Core MVC .NET Framework