Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Secure .NET Core Applications From CSRF Attacks: .NET Core Security Part II

DZone's Guide to

Secure .NET Core Applications From CSRF Attacks: .NET Core Security Part II

We continue our series on .NET Core security by looking at how to use the .NET Core framework to protect your web app against Cross-Site Request Forgery attacks.

· Security Zone ·
Free Resource

Discover how to provide active runtime protection for your web applications from known and unknown vulnerabilities including Remote Code Execution Attacks.

csrf4











This is the second post on .NET Core security. The first part can be found here.

In this post, we will see how to secure your .NET Core applications from CSRF attack.

What Is CSRF?

CSRF stands for Cross-Site Request Forgery.

Cross-Site Request Forgery (CSRF) is an attack where a malicious site sends a request to a vulnerable site where the user is currently logged in.

For example:

  • You logged in to the site X.com with form authentication.
  • The site will return an authentication cookie.
  • This cookie will travel along with the user's every request.
  • If the user visits a malicious siteY.com, the site may contain an HTML form with a submit button (or, really, any type of button).
  • If you click on the button, the form will be submitted to X.com instead of Y.com along with the authentication cookie.
  • The hacker can do whatever you want to do using your authentication code and they can post the form by running some scripts.
  • This can be so dangerous when the person is logged into, say, a banking application.

To prevent this, you need a token which will be included in the form and which will be validated server side when the user submits the form.

Let's See How .NET Core Handles This CSRF Attack

If we compare .NET Core with .NET as far as the resolution of CSRF attacks is concerned, The ValidateAntiForgeryToken attribute and the AntiForgeryToken HTML helper (@Html.AntiForgeryToken()) are still in both .NET and .NET Core. On top of these, there are some more powerful options in .NET Core.

Let's Explore These by Creating a .NET Core Application

Prerequisites:

  • Visual studio 2017 community edition, which can be downloaded here.
  • .Net Core 2.0 SDK, which can be downloaded here (I have written a post on how to install the SDK here).
  • We will use the code which I created during the code first sample, which is here. Details of the code are here in this post.

Token Generation

If you open the Create.cshtml page, then you will notice the below form tag:

<form asp-action="Creates">

Here asp* is a tag helper and the best part is that asp* tags will automatically add the token into your form when you submit the form.

For example, in below form, the __RequestVerificationToken is generated along with the form:

csrf1

Note: from .NET Core 2.0 onwards, the token is added even if you do not have asp* tags in your form.

Also, note that the simple form tag with action does not generate the token automatically. So if you have the below code in a razor file, then the token will not be generated automatically:

<form action="Creates">

In such cases, you can generate the token by adding @Html.AntiForgeryToken() under the form, as shown below:

<form action="Creates">
 @Html.AntiForgeryToken()
</form>

This will generate the token.

Restricting the Auto-Generation of Tokens

As .NET Core generates the token automatically, along with the form tag, you can even restrict this autogeneration if you do not wish to generate these tokens.

For this you need to add asp-antiforgery=”false” in the form tag, as demonstrated below:

<form asp-action="Creates"asp-antiforgery="false">

This will not generate the token for your form.

One more way to restrict this is using ! before the form tag, as shown below:

<!form asp-action="Creates">

! is called the Opt-out symbol.

Tokens With jQuery and Ajax

If you are using an Ajax call instead of using the form submit button, then you can use the below code to generate and send the token:

var csrfToken = $.cookie("CSRF-TOKEN");
 
$.ajax({
url: "/Employees/Creates",
contentType: "application/json",
data: JSON.stringify({  }), //// Data here
type: "POST",
headers: {
"X-CSRF-TOKEN": csrfToken
}
});

Validating the Anti-Forgery Token

Generally, a controller may contain GET as well as POST action methods. POST action methods require validating the anti-forgery token and not the GET action methods. So, if the ValidateAntiforgeryToken is declared on the controller, the HTTP GET requests become invalid, it would throw an error like below:

csrf3

I remember writing different code to resolve this issue. But with .NET Core, this is no longer necessary. AutoValidateAntiforgeryToken is your friend in such cases.

AutoValidateAntiforgeryToken

This is a new attribute added to the latest iteration of .NET Core.

Sometimes it is not required that you validate all the tokens, for example, with requests like:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

AutoValidateAntiforgeryToken is almost similar to ValidateAntiforgeryToken except for the fact that it doesn’t validate tokens on GET, HEAD, OPTIONS, and TRACE requests.

This filter can be applied either at the controller level or globally.

You can add an AutoValidateAntiforgeryToken filter above the action or above the controller, as shown below:

[HttpPost]
[AutoValidateAntiforgeryToken]
public async Task<IActionResult> Creates([Bind("EmployeeId,EmployeeName,EmployeeAge,DepartmentId")] Employee employee)
{
 
...

Or you can add it globally under the ConfigureService method of the Startup.cs class as demonstrated below:

services.AddMvc(options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

When you add this attribute globally, then you are not required to put the attribute above different actions as well as controllers.

ValidateAntiForgeryToken

This filter is the same as the one we have in the .NET MVC.

This filter validates the request token on each and every method it is placed on, regardless of the HTTP verb. So it even validates GET and HEAD requests, etc.

We can put this filter on the action method (or above the controller):

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Creates([Bind("EmployeeId,EmployeeName,EmployeeAge,DepartmentId")] Employee employee)
{
 
...
 
}

Or globally:

services.AddMvc(options =>
options.Filters.Add(new ValidateAntiForgeryTokenAttribute()));

Note: It is advisable to use AutoValidateAntiforgeryTokenAttribute rather than using ValidateAntiForgeryTokenAttribute globally because if we apply ValidateAntiForgeryTokenAttribute globally then we will not receive the anti-forgery tokens for certain types of requests like GET, HEAD, TRACE, etc. which will cause validation errors from those requests, as I explained above.

IgnoreAntiforgeryToken

Sometimes there might be some requirements for ignoring the anti-forgery tokens or you need to ignore the tokens for specific actions of the controllers. In such cases, you can use an IgnoreAntiforgeryToken filter.

For example, you want to ignore the tokens for any specific action of a controller. Then you can apply to the controller to that action:

[AutoValidateAntiforgeryToken]
public class EmployeesController : Controller
{
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> Creates([Bind("EmployeeId,EmployeeName,EmployeeAge,DepartmentId")] Employee employee)
{
 
...
 
}
 
}

Hope this helps!

Find out how Waratek’s award-winning application security platform can improve the security of your new and legacy applications and platforms with no false positives, code changes or slowing your application.

Topics:
.net core ,security ,web application security ,cross-site request forgery ,csrf attack prevention

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}