AntiForgery Token in ASP.NET Core MVC

Cross-Site Request Forgery and AntiForgeryToken in ASP.NET Core MVC

In this article, I will discuss Cross-Site Request Forgery and AntiForgery Token in ASP.NET Core MVC Applications with Examples. Please read our previous article discussing the Difference Between TypeFilter and ServiceFilter in ASP.NET Core MVC. In this article, first, I will discuss What is Cross-Site Request Forgery (CSRF or XSRF) with an example, and then I will show you how we can prevent the CSRF or XSRF attack using AntiForgery Token in ASP.NET Core MVC Applications.

What is a Cross-Site Request Forgery Attack?

Cross-Site Request Forgery (CSRF), also known as XSRF or Sea Surf, is a type of security attack that exploits the trust that a web application has in an authenticated user’s browser. This allows an attacker to perform actions on behalf of the authenticated user without their knowledge or consent. In a CSRF attack, the attacker tricks the victim into submitting a malicious request to a web application where they are authenticated, exploiting the user’s trust. If this is not clear at the moment, don’t worry; we will try to understand it with an example.

Example to Understand Cross-Site Request Forgery (CSRF or XSRF) Attack

Let us create a new ASP.NET Core Application using the Model-View-Controller Project template and give the project name BankingApplication. Once you create the project, modify the Home Controller as follows. So, our requirement is to create a view for updating the PIN of an Account Number of a user. In the below code, the Get version of the ChangePin action method will create a form where the user will enter his Account Number and Updated PIN and click on the PIN Change button. Once the User clicks on the PIN Change button, the form data will be submitted to the Post version of the ChangePin action method, which will process the data, update the PIN number, and then redirect to the PinChangeSuccess page.

using Microsoft.AspNetCore.Mvc;
namespace BankingApplication.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public IActionResult ChangePin()
        {
            return View();
        }

        [HttpPost]
        public ActionResult ChangePin(string AccountNumber, string Pin)
        {
            // Process the data
           
            TempData["Message"]= $"AccountNumber: {AccountNumber} Pin Changed to: {Pin}";

            return RedirectToAction("PinChangeSuccess");
        }

        public ActionResult PinChangeSuccess()
        {
            return View();
        }
    }
}
Creating the ChangePin View:

Next, create a view named ChangePin.cshtml within the Views/Home folder and then copy and paste the following code. Here, you can see we have one form with two text boxes and one submit button.

@{
    ViewData["Title"] = "Pin Change Page";
}

<div>
    <form asp-controller="Home" asp-action="ChangePin" method="post" class="mt-3">
        <div style="margin-top:7px" class="form-group row">
            <label for="AccountNumber" class="col-sm-2 col-form-label">Account Number</label>
            <div class="col-sm-10">
                <input type="text" name="AccountNumber" id="AccountNumber" class="form-control" />
            </div>
        </div>
        <div style="margin-top:7px" class="form-group row">
            <label for="Pin" class="col-sm-2 col-form-label">Pin</label>
            <div class="col-sm-10">
                <input type="text" name="Pin" id="Pin" class="form-control" />
            </div>
        </div>

        <div style="margin-top:10px" class="form-group row">
            <div class="col-sm-10">
                <button type="submit" class="btn btn-primary">PIN Change</button>
            </div>
        </div>
    </form>
</div>


Creating the PinChangeSuccess View:

Next, create a view named PinChangeSuccess.cshtml within the Views/Home folder and then copy and paste the following code. We are simply displaying the PIN Change Success message.

@{
    ViewData["Title"] = "PIN Change Success";
}

<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="alert alert-success mt-5" role="alert">
                <h4 class="alert-heading">Success!</h4>
                <p>@TempData["Message"]</p>
                <hr>
                <p class="mb-0">If you need to make any further changes, please return to your account settings.</p>
            </div>
        </div>
    </div>
</div>

Now, run the application, visit the Home/ChangePin, enter the Account Number and PIN, and then click on the PIN Change button as shown in the below image:

Example to Understand Cross-Site Request Forgery (CSRF or XSRF) Attack

Once you click on the PIN Change button, the PIN has been changed for the account number, and you should see the following success message:

What is a Cross-Site Request Forgery Attack

As you can see, the application is working as expected. Please observe the URL https://localhost:7199/Home/ChangePin. Now, let’s see how a hacker can use the above URL to launch a Cross-Site Request Forgery (CSRF or XSRF) attack.

Hackers Application:

Let us create a new ASP.NET Core Application using the Model View Controller Project template and give the project name HackerApplication. Once you create the HackerApplication, then modify the Home Controller as follows:

using Microsoft.AspNetCore.Mvc;
namespace HackerApplication.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

Next, modify the Index.cshtml view of the Home Controller of HackerApplication as follows. Here, you can see we are posting the form data to the Banking Application. We have a text field to store the Account Number and a hidden field to store some hard-coded PIN. Once the user clicks on the Claim My Gift Card button, the request will be submitted to the Banking Application, where it will update the Account Number and PIN.

@{
    ViewData["Title"] = "Claim Gift Card Page";
}

<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="text-center">
                <h3>Enter your Account Number to Claim Your Gift</h3>
                <form action="https://localhost:7199/Home/ChangePin" method="post" class="form-group">
                    <div class="form-group mt-3">
                        <input type="text" name="AccountNumber" id="AccountNumber" class="form-control" placeholder="Account Number" />
                    </div>
                    <div class="form-group mt-3">
                        <input type="hidden" name="Pin" id="Pin" value="1111" />
                        <button type="submit" class="btn btn-primary">Claim Your Gift</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

Now, run the application, enter your account number, and click the Claim Your Gift button, as shown in the image below.

Cross-Site Request Forgery and AntiForgeryToken in ASP.NET Core MVC

Once you click on the Claim Your Gift button, your account number pin is updated in the Banking Application as shown in the below image:

How we can Prevent Cross-Site Request Forgery (CSRF or XSRF) Attack in ASP.NET Core MVC

This is nothing but a Cross-Site Request Forgery (CSRF or XSRF) attack on a website.

How can we prevent Cross-Site Request Forgery (CSRF or XSRF) Attack in ASP.NET Core MVC?

To prevent Cross-Site Request Forgery (CSRF or XSRF) in ASP.NET Core MVC Web Applications, we need to use AntiForgery Tokens. ASP.NET Core MVC uses AntiForgery Tokens, also known as request verification tokens, to prevent CSRF attacks. These tokens are unique to each user session and confirm that the user submitting a request is the one who originally requested the page.

How Does It Work in ASP.NET Core?
  • When a form is rendered, ASP.NET Core MVC injects a hidden form field with the anti-forgery token.
  • The user’s browser submits this token along with the form data.
  • Upon receiving the request, the server validates the token to ensure that the request is legitimate.
How to Use AntiForgery Tokens in ASP.NET Core MVC?

To generate the anti-forgery token, we need to use the @Html.AntiForgeryToken() helper method within the <form> tag. Then, we need to decorate the action method that handles the posted form data with the [ValidateAntiForgeryToken] attribute. The [ValidateAntiForgeryToken] attribute will ensure that the action method processes the request only if it comes with a valid anti-forgery token.

From ASP.NET Core 2.0 onwards, the framework automatically generates anti-forgery tokens for all forms by default, so we don’t need to use the @Html.AntiForgeryToken() helper method. The framework validates the token automatically when the action method is decorated with the [ValidateAntiForgeryToken] attribute. If the token is missing or invalid, it rejects the request. So, let us proceed and implement this in our Banking Application:

Modify the ChangePin.cshtml view of the Home Controller of our banking application as follows. Here, we are adding the @Html.AntiForgeryToken() helper method within the form body. The @Html.AntiForgeryToken() method generates a hidden input field containing the anti-forgery token.

@{
    ViewData["Title"] = "Pin Change Page";
}

<div>
    <form asp-controller="Home" asp-action="ChangePin" method="post" class="mt-3">
        @Html.AntiForgeryToken()
        <div style="margin-top:7px" class="form-group row">
            <label for="AccountNumber" class="col-sm-2 col-form-label">Account Number</label>
            <div class="col-sm-10">
                <input type="text" name="AccountNumber" id="AccountNumber" class="form-control" />
            </div>
        </div>
        <div style="margin-top:7px" class="form-group row">
            <label for="Pin" class="col-sm-2 col-form-label">Pin</label>
            <div class="col-sm-10">
                <input type="text" name="Pin" id="Pin" class="form-control" />
            </div>
        </div>

        <div style="margin-top:10px" class="form-group row">
            <div class="col-sm-10">
                <button type="submit" class="btn btn-primary">PIN Change</button>
            </div>
        </div>
    </form>
</div>

Next, modify the Home Controller of our Banking Application as follows. Here, we are decorating the Post ChangePin action method with the ValidateAntiForgeryToken attribute. The [ValidateAntiForgeryToken] attribute ensures the request includes a valid anti-forgery or request verification token.

using Microsoft.AspNetCore.Mvc;
namespace BankingApplication.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public IActionResult ChangePin()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ChangePin(string AccountNumber, string Pin)
        {
            // Process the data
           
            TempData["Message"]= $"AccountNumber: {AccountNumber} Pin Changed to: {Pin}";

            return RedirectToAction("PinChangeSuccess");
        }

        public ActionResult PinChangeSuccess()
        {
            return View();
        }
    }
}

With the above changes, run the Banking Application; you will see that the account number pin updation functionality is working as expected. Now, run the Hacker Application and click on the Claim My Gift Card button by entering the Account, and you should see the following error page:

How to Use AntiForgery Tokens in ASP.NET Core MVC

The anti-forgery token filed name is __RequestVerificationToken, and if you want, you can also capture this field value in your application code. For example, modify the Home Controller of Banking Application as follows:

using Microsoft.AspNetCore.Mvc;
namespace BankingApplication.Controllers
{
    public class HomeController : Controller
    {
        [HttpGet]
        public IActionResult ChangePin()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ChangePin(string AccountNumber, string Pin, string __RequestVerificationToken)
        {
            // Process the data
           
            TempData["Message"]= $"AccountNumber: {AccountNumber} Pin Changed to: {Pin}";

            return RedirectToAction("PinChangeSuccess");
        }

        public ActionResult PinChangeSuccess()
        {
            return View();
        }
    }
}
How AntiForgeryToken Generated and Validated in ASP.NET Core MVC?

ASP.NET Core generates a unique token called the AntiForgeryToken when a form is rendered. This token is created using the @Html.AntiForgeryToken() helper method in Razor views. The generated token consists of two parts: a hidden field in the form and a cookie. The hidden field ensures the token is sent along with the form data during a POST request while the cookie is stored in the user’s browser. The token is encrypted and securely signed to ensure that it cannot be tampered with by an attacker. So, when we send the request to the server, the token is sent using the hidden form field as well as through the cookie header.

In ASP.NET Core MVC, when a form is submitted, the framework automatically validates the AntiForgeryToken if the [ValidateAntiForgeryToken] attribute is applied to an action method. During validation, the framework compares the token from the hidden field (sent in the POST request) with the token coming from the request header cookie. If the tokens do not match or are missing, ASP.NET Core will throw an exception, preventing the action method from executing, thereby stopping the potential CSRF attack.

In the next article, I will discuss Action Name Attributes in ASP.NET Core MVC. In this article, I explain Cross-Site Request Forgery and AntiForgeryToken in ASP.NET Core MVC Applications with Examples. I hope you enjoy this Cross-Site Request Forgery and AntiForgeryToken in the ASP.NET Core MVC article.

2 thoughts on “AntiForgery Token in ASP.NET Core MVC”

  1. Nice article, thanks. Very helpful.

    It’s worth mentioning that the tag helper automatically generates the token—so long as the form’s action isn’t specified manually—so the HTML helper technically is no longer needed.

  2. Nice article, thanks. Very helpful.

    It’s worth mentioning that the <form> tag helper automatically generates the token—so long as the form’s action isn’t specified manually—so the HTML helper technically is no longer needed.

Leave a Reply

Your email address will not be published. Required fields are marked *