Troubleshooting anti-forgery token problems

ぃ、小莉子 提交于 2019-11-26 18:45:53

I don't know if you mean you are able to get the error on demand - or you're seeing it in your logs but in any case here's a way to guarantee an antiforgery token error.

Wait for it...

  • Make sure you're logged out, then enter your login
  • Double click on the login button
  • You'll get :

The provided anti-forgery token was meant for user "", but the current user is "XXX@yahoo.com".

(For now I'm going to assume that this exact error message changed in MVC4 and that this is essentially the same message you're getting).

There's a lot of people out there that still double click on everything - this is bad! I just figured this out after just waking up so how this got through testing I really don't know. You don't even have to double click - I've got this error myself when I click a second time if the button is unresponsive.

I just removed the validation attribute. My site is always SSL and I'm not overly concerned about the risk. I just need it to work right now. Another solution would be disabling the button with javascript.

This can be duplicated on the MVC4 initial install template.

After help from Adam, I get the MVC source added to my project, and was able to see there are many cases that result in the same error.

Here is the method used to validate the anti forgery token:

    public void Validate(HttpContextBase context, string salt) {
        Debug.Assert(context != null);

        string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);

        HttpCookie cookie = context.Request.Cookies[cookieName];
        if (cookie == null || String.IsNullOrEmpty(cookie.Value)) {
            // error: cookie token is missing
            throw CreateValidationException();
        }
        AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value);

        string formValue = context.Request.Form[fieldName];
        if (String.IsNullOrEmpty(formValue)) {
            // error: form token is missing
            throw CreateValidationException();
        }
        AntiForgeryData formToken = Serializer.Deserialize(formValue);

        if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) {
            // error: form token does not match cookie token
            throw CreateValidationException();
        }

        string currentUsername = AntiForgeryData.GetUsername(context.User);
        if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
            // error: form token is not valid for this user
            // (don't care about cookie token)
            throw CreateValidationException();
        }

        if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) {
            // error: custom validation failed
            throw CreateValidationException();
        }
    }

My problem was that condition where it compares the Identity user name with the form token's user name. In my case, I didn't have the user name set (one was null, the other was an empty string).

While I doubt many will run into this same scenario, hopefully others will find it useful seeing the underlying conditions that are being checked.

AntiForgeryToken also checks your logged in user credentials haven't changed – these are also encrypted in the cookie. You can turn this off by setting AntiForgeryConfig.SuppressIdentityHeuristicChecks = true in the global.asax.cs file.

You should prevent double form submission. I prevent this type of issue using code like this:

$('#loginForm').on('submit',function(e){
    var $form = $(this);

    if (!$form.data('submitted') && $form.valid()) {
      // mark it so that the next submit can be ignored
      $form.data('submitted', true);
      return;
    }

    // form is invalid or previously submitted - skip submit
    e.preventDefault();
});

or

$('#loginForm').submit(function () {
    $(this).find(':submit').attr('disabled', 'disabled'); 
});

I just experienced an issue where @Html.AntiForgeryToken() was being called twice so the Anti-forger token was get screwed up in the HTTP Post payload.

Are you on one server or a web farm? If a single server, comment out your machineKey element in your web.config and try again as a base starting point. Any change? Also - can you think of any reasons your cookies would be getting cleared or expiring - they are required for this to work properly as well.

Is necessary check the form is it valid, before disable submit button.

<script type="text/javascript">
//prevent double form submission
$('form', '#loginForm').submit(function () {
    if ($(this).valid()) {
        $(this).find(':submit').attr('disabled', 'disabled');
    }
});

Another possible thing to check which has caused this error for me: I had two @Html.AntiForgeryToken() in one of my forms.

Once that was removed problem went away.

I also had this very same issue when I had to migrate my application to a new machine. I couldn't understand why this error suddenly manifested but felt certain it had something to do with the migration so started to investigate the registration of the database through aspnet_reqsql, when this was eliminated I realized it must be to do with the registration of the application and sure enough I found the answer in a similar place. I also on my journey discovered there are 2 ways to resolve this.

  1. ASP.NET automatically generates a cryptography key for each application and stores the key in the HKCU registry hive. When the application is migrated or accessed on a server farm these keys do not match, so method one is to add a unique machine key to the web.config. The machine key can be generated from IIS management console and added to the section of your web.config

    <machineKey validationKey="DEBE0EEF2A779A4CAAC54EA51B9ACCDED506DA2A4BEBA88FA23AD8E7399C4A8B93A006ACC1D7FEAEE56A5571B5AB6D74819CFADB522FEEB101B4D0F97F4E91" decryptionKey="7B1EF067E9C561EC2F4695578295EDD5EC454F0F61DBFDDADC2900B01A53D4" validation="SHA1" decryption="AES" />

  2. The second method is to grant access to the HKCU registry for the worker process through the appPool using AspNet_RegIIS and the switch -ga or for all apps using -i

aspnet_regiis -ga "IIS APPPOOL\app-pool-name"

Whichever method you choose should resolve this issue, but for my mind the most robust way for future migrations and server changes is going to be the unique key in the web.config, bearing in mind that this will cause the app to override the HKCU registry hive and keep you application running.

I just had a similar problem. I got:

The required anti-forgery form field "__RequestVerificationToken" is not present. 

What's of interest is that I tried debugging it and saw the token in both places I expected to find it in the controller

var formField = HttpContext.Request.Params["__RequestVerificationToken"];
var cookie = System.Web.HttpContext.Current.Request.Cookies["__RequestVerificationToken"].Value;

In reality I should have been looking here:

var formField = HttpContext.Request.Form["__RequestVerificationToken"];

As Params contains more than just the form fields, it contains the QueryString, Form, Cookies and ServerVariables.

Once that red herring was out of the way I found the AntiForgeryToken was in the wrong form!

html error logger is not correct line.

you must check all loading value in page is not null.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!