Before learning AntiForgeryToken, let's unfold the term forgery in day-to-day life. If someone copies someone's signature on a bank's cheque to withdraw money from his account, or anybody copies someone's work or art like copying the lyrics of music written by someone and show off it as his own work, all of these activities are called a forgery.
Nowadays almost everything has gone online, you can transfer money from your bank account to your friend or relative's bank account with some click only, the only condition is you must be logged in to your bank's website. Login to the bank website ensures that you are a valid customer of that bank.
Now again come to the term forgery, if anybody steals something from somewhere in the physical world then they are called a thief, similarly, if someone steals something online then they are called a Hacker. Hackers can even steal your identity and pretend to be you and can access everything, whatever you can access online. This act is termed digital forgery and we call it cybercrime.
Now let's take an example that will help us to understand AntiforgeryToken. Whenever we are Logged in to any website( account) then we can navigate anywhere within the site without logging in for each page(navigation), we can even request the same URL from another tab of our browser and the site does not ask us to log in. This is because, at the time of logging in, the site's server creates a secret cookie(can be considered as our identity for that site) and send it to our browser, if you request the same URL again within the same session meaning without closing the browser from any tab then the browser sends that secret cookie also with our request, on the other side the bank's server read the cookie and assures himself that it's you.
Now suppose you are logged in to your bank's website from your browser and some other site is also opened in another tab at the same time. You have opened the other site thinking that it is a gaming site but actually it is created by a hacker and when you click any button from such site a request from your browser to transfer money goes to your bank website. As the URL is the same your browser will send the cookie also and the bank's server thinks the request is coming from a trusted user (you) and processes the request. This is called CSRF that is a cross-site request forgery attack.
AntiforgeryToken is used to prevent such CSRF attacks. Let's first create a bank site with CSRF vulnerabilities and create another site to perform CSRF attack, in short, let's be a Hacker for a few minutes.
As you can see two tabs are open, in the first tab the hacker's site is opened, and on the second tab your bank site is opened, when you click the button on the hacker site a request to your bank site goes from your browser with all required values, as the URL is same, your browser sends the cookie too with the request to bank server and the bank server thinks it is a valid request and processes it like your normal request.
To understand CSRF attack completely, Create two projects one Bank site with two modules and other Hacker site with one module.
Bank Site:-
1. Login Module.
Here as soon as the user will log in a cookie will be created and send to the browser so for the next request onwards he will not need to login anymore within the same session.
2. Transaction Module.
Here we will create two methods one to return Data Entry Screen and other to transfer money .
And other as a Hacker site with one module only.
Hacker Site:-
Here will create a UI with a button ,and will create a form similar to bank website with hidden fields so that when the user will click it actually a request with required values will go to the bank site.
Bank Website:-
I)Login Module:-
create two Login method one to provide login screen and other to validate user and creating cookie. I am using forms authentication for this purpose.
[HttpGet]
public ActionResult Login(string ReturnUrl)
{
ViewBag.ReturnUrl = ReturnUrl;
return View();
}
[HttpPost]
public ActionResult Login(string UserName, string Password, bool RememberMe, string ReturnUrl)
{
if (UserName == "sachin" & Password == "sachin@7777")
{
FormsAuthentication.SetAuthCookie(UserName, RememberMe);
return Redirect(ReturnUrl);
}
return View("Login");
}
@{
ViewBag.Title = "Login";
}
<h2>Login</h2>
<form action="/Home/Login" method="post">
User Name:@Html.TextBox("UserName")
Password :@Html.Password("Password")
Remember Me:@Html.CheckBox("RememberMe")
@Html.Hidden("ReturnUrl", new { @value = ViewBag.ReturnUrl})
<button type="submit">Login</button>
</form>
To implement forms authentication add below lines to your webconfig.
<system.web>
<authentication mode="Forms">
<forms loginurl="~/Home/Login">
</forms>
</authentication>
<compilation debug="true" targetframework="4.5" />
<httpruntime targetframework="4.5" />
</system.web>
II)Transaction Module
Create two Action method one for returning Transfer money screen and other for processing the request and perform transaction.
public ActionResult TransferFund()
{
return View();
}
[Authorize]
public ContentResult MoneyTransfer(string Amount, string Account)
{
return Content("Amount" + Amount + " " + "successfully transfered to" + " " + Account);
}
@{
ViewBag.Title = "TransferFund";
}
<h2>TransferFund</h2>
<form action="/Home/MoneyTransfer" method="post">
<table>
<tr>
@Html.AntiForgeryToken()
<td>@Html.Label("Amount")</td>
<td>@Html.TextBox("Amount")</td>
</tr>
<tr>
<td>@Html.Label("Account No")</td>
<td>@Html.TextBox("Account")</td>
</tr>
<tr>
<td colspan="2"><button type="submit">Transfer Money</button></td>
</tr>
</table>
</form>
Now run the application you will get below results.
Do login with the password and User Name as specified in code and transfer money you will get below result.Hacker Site:-
Create One method to return a simple screen with the hidden fields and URL as bank site URL like below.
public ActionResult Index()
{
return View();
}
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form action="http://localhost:1075/Home/MoneyTransfer">
<table>
<tr>
@Html.Hidden("Amount", new { @value = "30000" })
</tr>
<tr>
@Html.Hidden("Account", new { @value = "3456782" })
</tr>
<tr>
<td colspan="2"><button type="submit">win 20000$</button></td>
</tr>
</table>
</form>
Now run both the application at a time ,and click win $2000 button of Hacker site.
You will be able to successfully transfer money and hence you become a hacker who knows how to perform a CSRF attack.
Now, in order to avoid CSRF attack In Asp.Net MVC we use AntiforgeryToken.
AntiForgeryToken:-
This is a secret token that is set on every UI, from where any important post request comes. For example, the bank website gives the user a screen to transfer money, this screen must contain the AntiForgeryToken, when post request comes from such UI (Form) then along with every required value the token also goes as a query string, on the other side the server validate this token and confirms that everything is alright.
So, let's add the AntiforgeryToken in TransferFund UI like below.
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form action="/Home/MoneyTransfer">
<table>
<tr>
@Html.AntiForgeryToken();
@Html.Hidden("Amount")
</tr>
<tr>
@Html.Hidden("Account")
</tr>
<tr>
<td colspan="2"><button type="submit">win 20000$</button></td>
</tr>
</table>
</form>
To Validate this Token Add ValidateAntiForgeryToken attribute to your Action Method like below.
[Authorize]
[ValidateAntiForgeryToken]
public ContentResult MoneyTransfer(string Amount, string Account)
{
return Content("Amount" + Amount + " " + "successfully transfered to" + " " + Account);
}
Notice in the code shown below, we have used AntiForgeryToken as an extension method of the Html helper class because it is nothing but an Html helper method that generates a hidden field with some unique value.
There is a myth that even if, It is good and reduces the chances of CSRF attack, but hackers are usually of a brilliant mind, they too can use AntiforgeryToken while creating Hidden form, so another version of AntiForgeryToken which accepts salt that is a unique value should be used, and that if you specify Salt in AntiForgeryToken then Salt+SecretCode merges to create a more unique Token. So we should always use the second version and specify Salt like below.
@Html.AntiForgeryToken("mySecret123")
Here mySecret123 is Salt which makes the token more unique.(myth)
Now in the server side to validate the Token add ValidateAntiForgeryToken attribute to the Action method like below.
[Authorize]
[ValidateAntiForgeryToken(Salt="mySecret123")]
public ContentResult MoneyTransfer(string Amount, string Account)
{
return Content("Amount" + Amount + " " + "successfully transfered to" + " " + Account);
}
But in reality the term Salt was misleading and of no use actually AntiForgeryToken generates a unique value for each user, so using Salt is unnecessary. That is why in the latest version of .Net Salt has been deprecated.