所需的防伪造cookie "__RequestVerificationToken"不存在。

40

我的网站每天会出现大约20次这个异常,通常表单都能正常工作,但是有时候会出现这个问题,我不知道为什么它如此随机。

这是由elmah记录的异常

500 HttpAntiForgery 所需的防伪造cookie "__RequestVerificationToken" 不存在。

但表单正在发送令牌,如elmah的XML日志所示。

<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>

这是我的控制器上的方法,该方法使用data属性来检查令牌是否有效

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

这是我在视图中的表单

@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>
}

这是我使用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;
});

这个表单大多数时候工作正常,但是出现了这个错误,我不知道为什么,我已经在Stack Overflow上检查了其他的问题,但是没有什么对我有用。

关于我如何提交数据的进一步解释。

这个发送短信的表单有ToNumber和Message两个字段。当用户点击提交按钮时,AJAX函数控制并序列化表单字段数据进行提交。当我的控制器中的函数完成并返回表示一切顺利的JSON结果时,AJAX方法重新加载页面,向用户显示成功消息。

有什么想法是什么原因导致了这个问题。

10个回答

46

听起来好像一切都按预期工作。

@Html.AntiForgeryToken()这个防伪助手的工作方式是通过在页面中注入名为__RequestVerificationToken的隐藏表单字段,并在浏览器中设置一个cookie。

当表单被提交时,两者将进行比较,如果它们不匹配或cookie丢失,则会抛出错误。

因此,Elmah记录表单正在发送__RequestVerificationToken并不重要。即使在CSRF攻击事件中,它也始终会存在,因为这只是隐藏的表单字段。

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

然而,错误消息表示相应的 COOKIE 没有被发送:

500 HttpAntiForgery 所需的防伪 cookie "__RequestVerificationToken" 不存在。

因此,基本上是有人或某物在重放表单提交,但没有进行原始请求以获取 cookie。因此,他们拥有隐藏的表单字段 __RequestVerificationToken,但没有用于验证它的 cookie。

因此,看起来一切都按预期运行。请检查您的日志记录,包括 IP 数字和引荐者等信息。您可能正在遭受攻击,或者在重定向表单内容时可能存在某些奇怪或错误的操作。像上面提到的,引荐者 是开始解决此类错误的好地方,假设这不是被欺骗的情况。

还要注意,根据MDN文档

location.reload();

Location.reload() 方法会重新加载当前 URL 所指向的资源。其可选参数为布尔型,当它为 true 时,将强制从服务器重新加载页面。如果它为 false 或未指定,则浏览器可能会从缓存中重新加载页面

如果偶然从缓存中加载,则可能会出现具有旧页面令牌但没有 cookie 的 POST 请求。

因此请尝试:

location.reload(true);

谢谢你详细的解释,我不知道 location.reload(true) 这个技巧。我刚刚修改了我的代码,明天等待一下看看是否还会出现这个问题,如果没有的话,我会接受你的答案。 - General Electric

30

最近遇到了类似问题。确实缺少防伪 cookie,所以(正如其他人指出的那样)可能是:

  1. 服务器没有将 cookie 添加到请求中,或者
  2. 浏览器拒绝了它。

在我的情况下,是服务器的问题:我在本地环境中没有使用 SSL,但在 web.config 中却有以下行:

<httpCookies requireSSL="True"/>

在这种情况下的解决方案是要么切换到SSL,要么将该值设置为“False”以用于本地环境。


3
在我们的情况下,当在本地项目之间切换时出现了问题,其中一些项目是SSL加密的,而另一些则没有。 - user1645826
1
我的XML验证器对True有意见,为了消除这个问题,请使用小写:true - General Grievance

9
除了rism的出色答案外,遇到此错误的另一个可能原因是您的浏览器或浏览器插件正在阻止设置cookie

4

我在Edge浏览器中遇到了同样的问题。

通过更改浏览器设置,我已经解决了这个问题。

按照以下说明修复该问题:

进入"设置" > "查看高级设置" > "Cookie" > 更改为 "不阻止Cookie"。

关闭浏览器并检查。

我认为这可能会帮助一些人。


0

可能需要看一下这个问题。在MVC 4中,防伪cookie令牌和表单字段令牌不匹配

这可能是一个超时问题。基本上当超时发生时,由于站点正在运行的iis用户没有适当的访问权限,因此不会存储cookie。对我来说,我将应用程序池更改为加载用户配置文件,这似乎解决了问题。


0

请检查您在前端代码中是否遗漏了此行 @Html.AntiForgeryToken()


0
在我的情况下,这与IIS上的缓存有关。我不得不在服务器管理器中重新启动整个IIS服务器。

0
尝试了上述解决方案,但错误仍然存在。进一步检查后发现,是由于我使用的浏览器设置引起的。
请不要使用下面突出显示的选项。它会导致无法存储 cookie,这就是你遇到错误的原因。

enter image description here


0
将 @Html.AntiForgeryToken() 放置在你的表单内。

0
我之前遇到过类似的情况,使用了 http://ip-address,后来改成了 https://ip-address,然后就可以正常工作了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接