Preventing Cross Site Request Forgery In MVC

In this blog, we will learn what is Cross-Site Request Forgery (CSRF) attack and how we can prevent CSRF in ASP.Net MVC. I have explained the whole process step by step.

What is Cross-Site Request Forgery

 
Cross-Site Request Forgery (CSRF) is a process in which a user first signs on to a genuine website (e.g. facebook.com) and after successful login, the user opens another website (malicious website) in the same browser.
 
Both websites are opened in the same browser. Malicious website will display some links to the user and asks the user to click on those links. User clicks on the links displayed on a malicious website, the malicious website sends a request using the existing session of genuine website. Web server of genuine website treats this request as a valid request and assumes that it is coming from a valid user so it executes the request and provides a proper response. A malicious website can perform harmful operations on genuine website.
 
In order to solve this problem, we expect the Action Method of genuine website to recognize the source of the request, whether the request is coming from genuine website or from a malicious website. This can be achieved by using the [ValidateAntiForgeryToken] attribute in ASP.Net MVC.
 

How to Implement CSRF Security in MVC

 
In order to implement CSRF security in MVC, first, we need to use HTML helper @Html.AntiForgeryToken() in view. It should be placed inside the BeginForm() method in view.
 
Next, we need to add [ValidateAntiForgeryToken] attribute on the action method which will accept HTTP post request. We need to do only these 2 changes and now MVC will prevent CSRF attacks.
 

How ValidateAntiForgeryToken works

 
How ValidateAntiForgeryToken prevents CSRF attacks?
 
Preventing Cross Site Request Forgery In MVC
 
First, the user will open genuine website in the browser. User login to genuine website. After login, genuine website sends Authentication cookie and Verification token. Verification token has randomly generated alphanumeric values. The verification token is stored in the cookie as well as in hidden field on client-side. When HTML form is submitted to the server, the verification token is submitted as a cookie as well as a hidden field. On the server-side, both are checked if they are same or not? If both are same then request is valid. If they are different or one of them is missing then request is treated as invalid request and will be rejected automatically by MVC.
 
When a user opens a malicious website in a new tab of the same browser, the malicious website will display some links and ask the user to click on those links. This website already has a script to send the request to genuine website. When the user clicks on links, the malicious website sends a request to genuine website. Since request is being sent to genuine website, the browser automatically submits Authentication cookie to Action method of genuine website but here, the hidden field is missing. The Action method has [ValidateAntiForgeryToken] attribute so it checks whether Authentication cookie and hidden field has same value but here, the hidden field is missing so the request is treated as invalid and it is rejected by MVC.
 

Practical Implementation

 
Wherever you have a Form, use @Html.AntiForgeryToken() inside the form and action method for accepting the HTTP Post should have ValidateAntiForgeryToken attribute. These are the only change, the rest of the process will be taken care of by ASP.Net MVC.
 
Please see the below HTML view where I have added@Html.AntiForgeryToken()
  1. @using (Html.BeginForm("Create""Products", FormMethod.Post, new { enctype = "multipart/form-data" }))  
  2. {  
  3.    @Html.AntiForgeryToken()  
  4.    <div class="form-row">  
  5.    <div class="form-group col-md-6">  
  6.       @Html.LabelFor(temp => temp.ProductName)  
  7.       @Html.TextBoxFor(temp => temp.ProductName, new { placeholder = "Product Name", @class = "form-control" })  
  8.       @Html.ValidationMessageFor(temp => temp.ProductName)  
  9.    </div>  
  10. <div class="form-group col-md-6">  
  11.    @Html.LabelFor(temp=>temp.Price)  
  12.    @Html.TextBoxFor(temp=>temp.Price,new { @class="form-control",placeholder="Price"})  
  13. </div>  
  14. </div>  
  15. @Html.ValidationSummary()  
  16.    <button type="submit" class="btn btn-success">Create</button>  
  17.    <a class="btn btn-danger" href="/products/index">Cancel</a>  
  18. }  
Below is the action method where I have added [ValidateAntiForgeryToken] attribute.
  1. [HttpPost]  
  2. [ValidateAntiForgeryToken]  
  3. public ActionResult Create(Product p)  
  4.    {  
  5.    ProductDBContext db = new ProductDBContext();  
  6.    if (ModelState.IsValid)  
  7.    {  
  8.       db.Products.Add(p);  
  9.       db.SaveChanges();  
  10.       return RedirectToAction("Index");  
  11.    }  
  12.    else  
  13.    {  
  14.       return View();  
  15. }  
  16. }  

Summary

 
In this blog, I have explained Cross-Site Request Forgery(CSRF), its steps and what changes we need to do in MVC application to prevent CSRF attacks.