Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The required anti-forgery cookie "__RequestVerificationToken" is not present

My website is raising this exception around 20 times a day, usually the form works fine but there are instances where this issue occur and I don't know why is so random.

This is logged exception by elmah

500 HttpAntiForgery The required anti-forgery cookie __RequestVerificationToken" is not present.

But the form it is sending the the token as shown on the XML log by elmah

<form>
    <item name="__RequestVerificationToken">
      <value string="DNbDMrzHmy37GPS6IFH-EmcIh4fJ2laezIrIEev5f4vOhsY9T7SkH9-1b7GPjm92CTFtb4dGqSe2SSYrlWSNEQG1MUlNyiLP1wtYli8bIh41"/>
    </item>
    <item name="toPhone">
      <value string="XXXXXX"/>
    </item>
    <item name="smsMessage">
      <value string="xxxxxxxx"/>
    </item>
</form>

This is my method on the controller which uses the data Attribute to check if the token is valid or nor

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Send(SMSModel model)
{
    // my code goes here
}

This is my form on the view

@using (Html.BeginForm("Send", "SMS", FormMethod.Post, new { @class = "form-sms", autocomplete = "off" }))
{
    @Html.AntiForgeryToken()
    <div class="row">
        <div class="col-md-12">
            <div class="form-group">
                <div class="input-group">
                    <div class="input-group-addon">+53</div>
                    @Html.TextBoxFor(m => m.toPhone, new { @class = "form-control", placeholder = "teléfono", required = "required", type = "tel", maxlength = 8 })
                </div>
            </div>
        </div>
    </div>
    <div class="form-group" style="position:relative">
        <label class="sr-only" for="exampleInputEmail3">Message (up to 135 characters)</label>
        @Html.TextAreaFor(m => m.smsMessage, new { rows = 4, @class = "form-control", placeholder = "escriba aquí su mensaje", required = "required", maxlength = "135" })
        <span class="char-count">135</span>
    </div>
    if (ViewBag.Sent == true)
    {
        <div class="alert alert-success alert-dismissible" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <strong>Su mensaje ha sido enviado <span class="hidden-xs">satisfactoriamente</span></strong>
        </div>
    }
    if (ViewBag.Error == true)
    {
        <div class="alert alert-danger alert-dismissible" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <strong>Error:</strong> Por favor revise el número de teléfono.
        </div>
    }
    <div class="errorToMany"></div>
    <button type="submit" class="btn btn-default btn-block">Enviar SMS</button>
}

And this how I post my data using AJAX

$('form.form-sms').submit(function (event) {
    $.ajax({
        url: $(this).attr("action"),
        type: "POST",
        data: $(this).serializeArray(),
        beforeSend: function (xhr) {
            $('.btn-default').attr("disabled", true);
            $('.btn-default').html("Enviando...")
        },
        success: function (data, textStatus, jqXHR) {
            if (data[0] == false && data[1] == "1") {
               some code 
            } else {
               location.reload();
            }
        },
        error: function (jqXHR, textStatus, errorThrown) { }
    });
    return false;
});

The form works well most time but this error keeps happening and I don't know why, I've checked other questions here on Stack Overflow but nothing works for me.

For further explanation about how I post the data.

This form to send SMS has the fields ToNumber and Message. When a user clicks on the submit Button the AJAX function takes control and post it serializing the form's field data, when my function in the controller finishes and return the JSON result indicating everything went well, the AJAX method reloads the page showing the user a success message.

Any ideas what could be causing this issue.

like image 200
General Electric Avatar asked Oct 23 '15 16:10

General Electric


People also ask

What is __ Requestverificationtoken cookie?

__RequestVerificationToken. www.grpgroup.co.uk. This is an anti-forgery cookie set by web applications built using ASP.NET MVC technologies. It is designed to stop unauthorised posting of content to a website, known as Cross-Site Request Forgery.

What is Requestverificationtoken?

To help prevent CSRF attacks, ASP.NET MVC uses anti-forgery tokens, also called request verification tokens. The client requests an HTML page that contains a form. The server includes two tokens in the response. One token is sent as a cookie. The other is placed in a hidden form field.

What does HTML AntiForgeryToken () do?

AntiForgeryToken()Generates a hidden form field (anti-forgery token) that is validated when the form is submitted.


3 Answers

It almost sounds as if things are working as expected.

The way the anti forgery helper @Html.AntiForgeryToken() works is by injecting a hidden form field named __RequestVerificationToken into the page AND it also sets a cookie into the browser.

When the form is posted back the two are compared and if they don't match or the cookie is missing then the error is thrown.

So it does not matter that Elmah logs that the form is sending __RequestVerificationToken. It always will, even in the event of CSRF attack, because this is simply the hidden form field.

<input name="__RequestVerificationToken" type="hidden" value="DNbDMrzHmy37GPS6IFH-EmcIh4fJ2laezIrIEev5f4vOhsY9T7SkH9-1b7GPjm92CTFtb4dGqSe2SSYrlWSNEQG1MUlNyiLP1wtYli8bIh41" />

The error message on the other hand says the corresponding COOKIE is not being sent:

500 HttpAntiForgery The required anti-forgery cookie __RequestVerificationToken" is not present.

So basically someone/something is replaying the form post without making the original request to get the cookie. As such they have the hidden form field __RequestVerificationToken but NOT the cookie to verify it.

So it seems like things are working as they should. Check your logs re: IP numbers, and referrers, etc. You might be under attack or perhaps be doing something weird or buggy when redirecting your form content. As above, referrers are a good place to start for this kind of error, assuming this is not being spoofed.

Also note that as per MDN

location.reload();

The Location.reload() method reloads the resource from the current URL. Its optional unique parameter is a Boolean, which, when it is true, causes the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.

If it is, on occasion loading from cache, then you might end up with a POST that has the old page token but not the cookie.

So try :

location.reload(true);
like image 194
rism Avatar answered Oct 18 '22 21:10

rism


Ran into similar issue recently. The anti-forgery cookie indeed was missing, so (as others pointed out) either

  1. the server did not add the cookie to request, or
  2. the browser rejected it.

In my case, it was the server: I was not using SSL on local environment, yet in web.config I had the following line:

<httpCookies requireSSL="True"/>

Solution in this case is to either switch to SSL, or keep the value set to 'False' for local environment.

like image 29
Rod Borchevskyi Avatar answered Oct 18 '22 22:10

Rod Borchevskyi


In addition to rism's excellent answer, another possible reason for encountering this error is because your browser, or browser plugin is blocking cookies from being set.

like image 9
Samuel Liew Avatar answered Oct 18 '22 22:10

Samuel Liew