Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC3 AntiForgeryToken

Here I have simple MVC3 application with two form posts. To protect CSRF attack, I have used antiforgerytoken html helpers in both forms as per guidance here.

Here are my two models:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}


public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Here is my homeController.cs:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index(User user)
    {
        if (ModelState.IsValid)
            return RedirectToAction("About");

        return View();
    }

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

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult About(Employee employee)
    {
        if (ModelState.IsValid)
            return RedirectToAction("PageA");

        return View();
    }
}

Here is my Inex.cshtml:

@model MvcAntiforgeryToken.Models.User

@using (Html.BeginForm()) {

@Html.AntiForgeryToken()
<div>
    <fieldset>
        <legend>User Information</legend>

        <div class="editor-label">
            @Html.LabelFor(m => m.FirstName)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.FirstName)
            @Html.ValidationMessageFor(m => m.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(m => m.LastName)
        </div>
        <div class="editor-field">
            @Html.PasswordFor(m => m.LastName)
            @Html.ValidationMessageFor(m => m.LastName)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</div>

}

Here is my About.cshtml:

@model MvcAntiforgeryToken.Models.Employee

@using (Html.BeginForm()) {

@Html.AntiForgeryToken()
<div>
    <fieldset>
        <legend>Employee Information</legend>

        <div class="editor-label">
            @Html.LabelFor(m => m.Id)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.Id)
            @Html.ValidationMessageFor(m => m.Id)
        </div>

        <div class="editor-label">
            @Html.LabelFor(m => m.Name)
        </div>
        <div class="editor-field">
            @Html.PasswordFor(m => m.Name)
            @Html.ValidationMessageFor(m => m.Name)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</div>

}

Posting of Home/Index:

when user visits Home/Index, application created "RequestVerificationToken_Lw" cookie with value "pG2/E00Q2DngYxs98f92x9qqrIvrh6zCT/+GGte67NFZLazKFlz++QqMSHpkZ08Qum9vsBCtq7O7MSzCawJkEa2/hdjrWoAcHlDWxxYRWKXm+OxPbqlRs609zam4fK7hReGEX3zf8YR4ltH3oYf4AZgt2mZV31ihRGShiZ7Oy9k="

and following hidden form input

<input name="__RequestVerificationToken" type="hidden" value="B1KKzYEFEdINnuhy53MqqxHCHELPUd5pX3vRqYWz1+pkhBA6YGFvSVtXgSURkAn3yNwee3nrqDCMXB8MB0SWiUU3GuHnhH7+Qc1IQebJHoFJZR2CPXNOmUzINXbBWKZz+35pQQQXdiKptR3raLSoElfQi18ZC4Pr7xNREGIOM2A=" /> 

Posting of Home/About:

when user visits Home/About, application created "RequestVerificationToken_Lw" cookie with value "pG2/E00Q2DngYxs98f92x9qqrIvrh6zCT/+GGte67NFZLazKFlz++QqMSHpkZ08Qum9vsBCtq7O7MSzCawJkEa2/hdjrWoAcHlDWxxYRWKXm+OxPbqlRs609zam4fK7hReGEX3zf8YR4ltH3oYf4AZgt2mZV31ihRGShiZ7Oy9k="

and following form input

<input name="__RequestVerificationToken" type="hidden" value="UOCMATdy93A0230aBmRPv5F0xpJlI2urE5sJ4nxsTSWrsi9/xM5qhrxQ4I2vWIjvVrhkW8gSgmGFp7c4XPQUQG5myMGipTAr2/mi5od+Sz6IcfrF2FxwjfWMslt96BcMG6b9BjaGbgnClQOVTkjfHEMIptOYUCTSbVK61dWp5qI=" /> 

Here is my questions:

  1. why "RequestVerificationToken_Lw" cookie value is same in both forms? shoudn't it be recreated for every form posts?

  2. why "RequestVerificationToken_Lw" cookie value and "__RequestVerificationToken" hidden input values are different ?

Thanks much for your responses!

like image 842
matmat Avatar asked Jan 20 '13 05:01

matmat


1 Answers

The idea of the CSRF attack vector is this: I put up a malevolent form on my website https://fake-domain-that-looks-like-a-bank.com. I took the HTML and CSS from your site, so it looks exactly the same. I have a valid cert and all the logo bells and whistles. Now I trick users into visiting my site.

The user sees the usual form and does something. However, I replaced some of the inputs so they go nowhere, and I added some hidden fields so I control what the user does (involuntarily), like replace 'op=modify with op=delete. All his actions are backed by his (valid) auth cookie.

Now the anti forgery token protects the user because as the attacker, I can't add a valid hidden field that matches his cookie to my form. If I could read his cookies somehow, I could simply steal the auth token which would be a lot easier.

In MVC, the anti forgery token is bound to the logged on user's name. If you're using FormsAuthentication and change the structure of user names, all users with existing cookies will run into trouble. As a side note: a common problem is that users who maintain two accounts run into AntiForgeryTokenExceptions, you might want to handle that if it is a valid usage scenario.

To address the actual questions:

Why does the cookie not change

If the cookie value changed with every request, multi-tab browsing would be a problem.

Why are cookie and form value different

MVC's cookies have internal structure, so their serialized version looks different. The actual security token that is inside should be identical. The serializer stores different information, depending on what information is present (user identity name, etc.). There is also a version byte, an indicator whether this is a session cookie, etc.

Gritty Details

If you want to know more, I recommend you clone the source via http://aspnetwebstack.codeplex.com/ and look at System.Web.WebPages\Helpers\AntiXsrf\TokenValidator.cs, among other files. It's quite helpful to have the source around in any case.

like image 136
mnemosyn Avatar answered Sep 28 '22 02:09

mnemosyn