Validateantiforgerytoken Purpose, Explanation and Example

ValidateAntiForgeryToken purpose, explanation and example

MVC's anti-forgery support writes a unique value to an HTTP-only cookie and then the same value is written to the form. When the page is submitted, an error is raised if the cookie value doesn't match the form value.

It's important to note that the feature prevents cross site request forgeries. That is, a form from another site that posts to your site in an attempt to submit hidden content using an authenticated user's credentials. The attack involves tricking the logged in user into submitting a form, or by simply programmatically triggering a form when the page loads.

The feature doesn't prevent any other type of data forgery or tampering based attacks.

To use it, decorate the action method or controller with the ValidateAntiForgeryToken attribute and place a call to @Html.AntiForgeryToken() in the forms posting to the method.

ValidateAntiForgeryToken attribute

The ValidateAntiForgeryToken attribute is used to prevent forgery of requests. Request validation is needed to secure your MVC application.
It works by adding a new 'Anti Forgery Token' hidden field to your form and a cookie; and then validating/comparing the two in a POST request.
Here is an article that explains in more detail how the anti-forgery mechanism works.

What does '[ValidateAntiForgeryToken]' truly mean?

In simple words it prevents external post requests. So, nobody can use your methods from other sites.

How it works. You are having AntiForgeryToken in your Html.BeginForm in View.

@using (Html.BeginForm()){

@Html.AntiForgeryToken()

//** fields of form

}

When you submit form, you sends data to your Controller method. If method has ValidateAntiForgeryToken attribute, it validates if data you are sending has your ForgeryToken.

[ValidateAntiForgeryToken]
public ViewResult Update()
{
}

ForgeryToken is generated once per session.

How to use ValidateAntiForgeryToken at controller level in MVC?

From http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/

Limitations of the Anti-Forgery helpers

It only works with POST requests, not GET requests. Arguably this isn’t a limitation, because under the normal HTTP conventions, you shouldn’t be using GET requests for anything other than read-only operations.

So it isn't useful at the controller level.

ASP.NET Core

[ValidateAntiforgeryToken] on the controller has limitations.

https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1

ASP.NET Core doesn't support adding antiforgery tokens to GET requests automatically.

Controller-level support is improved with [AutoValidateAntiforgeryToken]

This attribute works identically to the ValidateAntiForgeryToken attribute, except that it doesn't require tokens for requests made using the following HTTP methods:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

What is the use of @Html.AntiForgeryToken()?

This is a security feature to help protect your application against cross-site request forgery.

Example:

Let's assume you have a register functionality in your web app. You have an AccountController (example.com/account/register) where you expect people to submit their info. Normally before someone posts the registration information needs to visit the actual (example.com/account/register) than submit the form.

Let say I am a bad guy and I want to flood your server with junk info all I need to do is just keep posting directly to (example.com/account/register) without visiting your site. So in order to stop me you implement AntiForgeryToken so you can make it sure I visited the page before I submitted the registration information.

Another example is http://www.binaryintellect.net/articles/20e546b4-3ae9-416b-878e-5b12434fe7a6.aspx.

ValidateAntiForgeryToken in WebForms Application

I found this article How To Fix Cross-Site Request Forgery (CSRF) using Microsoft .Net ViewStateUserKey and Double Submit Cookie with the following information code and instructions:

Starting with Visual Studio 2012, Microsoft added built-in CSRF protection to new web forms application projects. To utilize this code, add a new ASP .NET Web Forms Application to your solution and view the Site.Master code behind page. This solution will apply CSRF protection to all content pages that inherit from the Site.Master page.

The following requirements must be met for this solution to work:

•All web forms making data modifications must use the Site.Master
page.

•All requests making data modifications must use the ViewState.

•The web site must be free from all Cross-Site Scripting (XSS)
vulnerabilities. See how to fix Cross-Site Scripting (XSS) using
Microsoft .Net Web Protection Library for details.

public partial class SiteMaster : MasterPage
{
private const string AntiXsrfTokenKey = "__AntiXsrfToken";
private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
private string _antiXsrfTokenValue;

protected void Page_Init(object sender, EventArgs e)
{
//First, check for the existence of the Anti-XSS cookie
var requestCookie = Request.Cookies[AntiXsrfTokenKey];
Guid requestCookieGuidValue;

//If the CSRF cookie is found, parse the token from the cookie.
//Then, set the global page variable and view state user
//key. The global variable will be used to validate that it matches in the view state form field in the Page.PreLoad
//method.
if (requestCookie != null
&& Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
{
//Set the global token variable so the cookie value can be
//validated against the value in the view state form field in
//the Page.PreLoad method.
_antiXsrfTokenValue = requestCookie.Value;

//Set the view state user key, which will be validated by the
//framework during each request
Page.ViewStateUserKey = _antiXsrfTokenValue;
}
//If the CSRF cookie is not found, then this is a new session.
else
{
//Generate a new Anti-XSRF token
_antiXsrfTokenValue = Guid.NewGuid().ToString("N");

//Set the view state user key, which will be validated by the
//framework during each request
Page.ViewStateUserKey = _antiXsrfTokenValue;

//Create the non-persistent CSRF cookie
var responseCookie = new HttpCookie(AntiXsrfTokenKey)
{
//Set the HttpOnly property to prevent the cookie from
//being accessed by client side script
HttpOnly = true,

//Add the Anti-XSRF token to the cookie value
Value = _antiXsrfTokenValue
};

//If we are using SSL, the cookie should be set to secure to
//prevent it from being sent over HTTP connections
if (FormsAuthentication.RequireSSL &&
Request.IsSecureConnection)
responseCookie.Secure = true;

//Add the CSRF cookie to the response
Response.Cookies.Set(responseCookie);
}

Page.PreLoad += master_Page_PreLoad;
}

protected void master_Page_PreLoad(object sender, EventArgs e)
{
//During the initial page load, add the Anti-XSRF token and user
//name to the ViewState
if (!IsPostBack)
{
//Set Anti-XSRF token
ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;

//If a user name is assigned, set the user name
ViewState[AntiXsrfUserNameKey] =
Context.User.Identity.Name ?? String.Empty;
}
//During all subsequent post backs to the page, the token value from
//the cookie should be validated against the token in the view state
//form field. Additionally user name should be compared to the
//authenticated users name
else
{
//Validate the Anti-XSRF token
if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
|| (string)ViewState[AntiXsrfUserNameKey] !=
(Context.User.Identity.Name ?? String.Empty))
{
throw new InvalidOperationException("Validation of
Anti-XSRF token failed.");
}
}
}

}

Set ValidateAntiForgeryToken Attribute to work on a condition

If you decorate the controller action method with ValidateAntiForgeryToken attribute, you can not escape by not putting the hidden field in the view.

You need to figure out a way where, you have the ValidateAntiForgeryToken attribute, have the hidden field for the token in the view but validate the token only when needed.

For the below solution, I assume that the multiple applications you are talking about has web.config file.

What you need to do is, introduce a new configuration in appSettings, such as IsAntiForgeryTokenValidationEnabled or some better shorter name.

Create a new attribute class as following and check the configuration value. If the configuration value is true go ahead and validate the token else just skip it.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CheckAntiForgeryTokenValidation : FilterAttribute, IAuthorizationFilter
{
private readonly IIdentityConfigManager _configManager = CastleClassFactory.Instance.Resolve<IIdentityConfigManager>();
public void OnAuthorization(AuthorizationContext filterContext)
{
var configValue = System.Configuration.ConfigurationManager.AppSettings["IsAntiForgeryTokenValidationEnabled"];
//Do not validate the token if the config value is not provided or it's value is not "true".
if(string.IsNullOrEmpty(configValue) || configValue != "true")
{
return;
}
// Validate the token if the configuration value is "true".
else
{
new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
}
}
}

OnAuthorization method of above class will be executed before the action method where this attribute is used and validate or not validate the token based on the configuration value.

Now you need to use this attribute on the controller action method as following example.

public class HomeController : Controller
{
[HttpPost]
[CheckAntiForgeryTokenValidation]
public ActionResult Save()
{
// Code of saving.
}
}

After this all the applications which want to validate the AntiForgeryToken need to have the configuration IsAntiForgeryTokenValidationEnabled in their configuration file with value true. The token validation is not available by default, so if existing applications don't have the configurations, they still work without any issues.

I hope this would help you resolve your issue.

Does ValideAntiForgeryToken prevent falsifying of POST parameters?

There is no way for a user to pass a different itemListId to the above step, because it is passed by the webpage when they submit the form

This is false. The AntiForgeryToken will not protect you from altered data.

  1. Make a GET request to Item/Add/4. I assume you will have a form on this page. You can include the @Html.AntiForgeryToken().

  2. Use your browser's debug tools to inspect the form.

    • Now you can edit the action attribute to directly modify Item/Add/5 the value.
    • Or modify any <input> field value.
  3. Put a debug break on your POST action and you will see the altered values when you submit the form.

The above is not the only way to tamper with the data. Therefore, you should always validate any input.

[Authorize, ValidateAntiForgeryToken]
[HttpPost]
public ActionResult NukeMyBankAccount(int accountId)
{
var account = db.GetAccount(accountId);

// validate
if (CurrentUser.Id != account.Owner.Id)
{
return RedirectToAction("Unauthorized");
}
else
{
db.NukeAccount(accountId, areYouSure: true);
}
...
}

Do I need to use `[ValidateAntiForgeryToken] and @Html.AntiForgeryToken()` on all my pages?

Think of the antiforgerytoken is a way of ensuring that the request that is coming to a post action is actually one that originated from your outputted view. It stops cross site scripting attacks and i think it handles post replay attacks too.

Securing the front door to your application is a good start, it stops people having their data stolen by brute force, however, it doesn't stop all forms of attacks. things like social engineering and phishing can let someone in to your site without them breaking the login page.

Once in, there are all sorts of nastiness that they can get up to, so look at the OSWAP recommendations and see if there are any other attacks that you might be vulnerable to. http://www.ergon.ch/fileadmin/doc/Airlock_Factsheet_OWASP_en.pdf

If in doubt, you can have your site pen tested by ethical hackers for a few hundred stirling, if you are looking after sensitive data, then i would recommend that, as they will pull up things that you might not even think of.

My top tips for security

  1. Antiforgerytoken on the login page
  2. Slow all authentication attempts down by at least a second (makes brute force impractical)
  3. Implement an account lock out procedure on n amounts of invalid logons
  4. Always use a generic error message on your failed logins to prevent hackers knowing which part of a login is wrong
  5. Always encrypt your passwords in the db with a salt, the salt should be per user to prevent a rainbow attack on a stolen database
  6. Always make sure that any data displayed or retrieved is valid for that user
  7. Always use parameterised sql
  8. Try and obfuscate the ids passed around in your urls and views to prevent modification or an attempt at a direct reference attack

Following that, I think you will cover off most of what a pen test would raise and set you on a good stead for a secure site



Related Topics



Leave a reply



Submit