In this blog we will get to know about the way to prevent CSRF (Cross Site Request Forgery) attacks in ASP.NET MVC applications. If you want to have some idea about this attack you would like to have a look at this blog http://findnerd.com/list/view/What-is-Cross-Site-Request-Forgery/22640/.
One important point to note here is that ASP.NET MVC framework has provided easy to use tools which can be easily implemented. So assuming you have taken initial understanding of CSRF attack, let us try to find the cause for this attack.
Cause of the CSRF attack
As we know that we have access to many websites on the internet, many of these websites also provides you different online services like banking, shopping, tax return and so on. Obviously many of the provided services are very crucial from information point of view and if accessed with wrong intention might result in a big loss to a user.
One of the basic security hole which allow such attacks is lack of identification of original source. In other words, it doesn't matter whether requests are originating from an authenticated source or not but they will be equally effective in executing a specific functionality. Let us try to investigate this situation with the help of an example.
Example of CSRF attack in ASP.NET MVC
Suppose we have a bank website which has a POST method "Transfer" to transfer the money in an account. In this example, we assume that authenticated user is accessing the bank website and Transfer method should only be accessible to authenticated user with the help of user interface provide by the bank website. But what will happen, if Transfer method doesn't have any prevention against possible CSRF attacks. In such case Transfer method would also be accessible outside the website.
Before we see this attack in action, let us assume that bank application is created using ASP.NET MVC and components related to Transfer method are designed as follows.
Model class representing the Transfer
public class TransferViewModel
{
[Required]
Display(Name = "Account Holder")]
public string AccountHolder { get; set; }
[Required]
Display(Name = "Amount To Transfer")]
public decimal Amount { get; set; }
}
UI component of Transfer page
@using BankApplication.Models
@model TransferViewModel
@{
ViewBag.Title = "Transfer";
}
<div class="row">
@using (Html.BeginForm("Transfer", "Account", FormMethod.Post))
{
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.LabelFor(m => m.AccountHolder, new { @class = "col-md-2 control-label" })
@Html.TextBoxFor(m => m.AccountHolder, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.AccountHolder, "", new { @class = "text-danger" })
<br />
@Html.LabelFor(m => m.Amount, new { @class = "col-md-2 control-label" })
@Html.TextBoxFor(m => m.Amount, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Amount, "", new { @class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Transfer Amount" class="btn btn-default" />
</div>
</div>
}
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Transfer action inside AccountController
public class AccountController : Controller
{
[Authorize]
public ActionResult Transfer()
{
// Render the view to allow input details for transfer
return View();
}
[HttpPost]
[Authorize]
public ActionResult Transfer(TransferViewModel model)
{
// Transfer functionality implemented here...
return View(model);
}
}
Let's check scenario of possible CSRF attack in following steps.
Step-1 Authenticated user is accessing the website http://www.bank.com.
Step-2 An attacker crafted an e-mail with following content and send it to that authenticated user.
<form action="http://www.bank.com/Account/Transfer" method="POST">
<input type="hidden" name="AccountHolder" value="Attacker"/>
<input type="hidden" name="Amount" value="3000"/>
<input type="submit" value="Click here to find perfect partner!"/>
</form>
Notice that this mail contains hidden fields which will be used as a parameter for Transfer method. One of the hidden field with name as "AccountHolder" will transfer amount 3000 to Attacker's account. This mail may be taken as a normal mail because it doesn't show anything except a link with "Click here to find perfect partner!".
Step-3 Authenticated user open up this mail and click on button with text "Click here to find perfect partner!" and may end up with transferring money to Attacker's account.
Prevention from CSRF attacks in ASP.NET MVC
To prevent such kind of CSRF attacks in ASP.NET MVC applications we must use
@Html.AntiForgeryToken()
syntax in the view which will create a hidden input field "__RequestVerificationToken" holding a random string in encrypted format. Everytime you refresh your screen it will get a new encrypting string value. A sample of hidden field "__RequestVerificationToken" is shown as follows:
<input name="__RequestVerificationToken" type="hidden" value="MYf4r3zT4Mr8M5dnFy8U-jWdCw5rQfP3kMmxrBHO5gnKMm-r84-ZyuEh7p7xEZT7z14BrdnpFrevStjs88zetrqG7wQas99xRrmpne1DQT01" />
At the same time on checking the browser cookies, you will also notice that a cookie with the same name "__RequestVerificationToken" also gets created inside the same domain as of the website. But this is not enough as the POST method which is actually responsible for transferring the amount doesn't have any check to validate the request. Now let's add an attribute [ValidateAntiForgeryToken] in the POST method and our method will look like as follows:
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult Transfer(TransferViewModel model)
{
// Transfer functionality implemented here...
return View(model);
}
Now even if user will be tricked to click any malicious link targeting this POST method, it won't get executed and shows following exception on browser.
The required anti-forgery form field "__RequestVerificationToken" is not present.
It shows that the source which is initiating the request to access this POST method doesn't have "__RequestVerificationToken" field to be matched with the value of the cookie with same name i.e, "__RequestVerificationToken".
Let us summarize our findings now. By adding a call to helper method
@Html.AntiForgeryToken()
in the view, we mark the view as the valid source to submit a request. It results in creating a hidden field as well as the cookie with same name both having long string values in encrypted form. Their values will be compared for equality while submitting a request to an action method. Now we also need to mark our method secured in the way that it should be accessed only from the source having valid hidden field value and that too matching with the value of the cookie. Here you have another reason why methods responsible for state changing requests on server should be marked as POST for the sake of security. :)
Hope it helps you in getting basic understanding of inbuilt functionalities provided in ASP.NET MVC framework to prevent CSRF attacks.
0 Comment(s)