解决防伪令牌问题

发布于 2024-11-03 11:17:38 字数 1072 浏览 1 评论 0原文

我有一个表单帖子始终给我一个防伪令牌错误。

这是我的表单:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Birthday)
    <p>
        <input type="submit" id="Go" value="Go" />
    </p>
}

这是我的操作方法:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Join(JoinViewModel model)
{
    //a bunch of stuff here but it doesn't matter because it's not making it here
}

这是 web.config 中的 machineKey:

<system.web>
  <machineKey validationKey="mykey" decryptionKey="myotherkey" validation="SHA1" decryption="AES" />
</system.web>

这是我得到的错误:

未提供所需的防伪令牌或该令牌无效。

我读过,更改 HttpContext 上的用户将使令牌无效,但这里不会发生这种情况。我的 Join 操作上的 HttpGet 仅返回视图:

[HttpGet]
public ActionResult Join()
{
    return this.View();
}

所以我不确定发生了什么。我四处搜索,一切似乎都表明要么是 machineKey 更改(应用程序周期),要么是用户/会话更改。

还有什么可能发生的事情?我该如何解决这个问题?

I have a form post that consistently gives me an anti-forgery token error.

Here is my form:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Birthday)
    <p>
        <input type="submit" id="Go" value="Go" />
    </p>
}

Here is my action method:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Join(JoinViewModel model)
{
    //a bunch of stuff here but it doesn't matter because it's not making it here
}

Here is the machineKey in web.config:

<system.web>
  <machineKey validationKey="mykey" decryptionKey="myotherkey" validation="SHA1" decryption="AES" />
</system.web>

And here is the error I get:

A required anti-forgery token was not supplied or was invalid.

I've read that changing users on the HttpContext will invalidate the token, but this isn't happening here. The HttpGet on my Join action just returns the view:

[HttpGet]
public ActionResult Join()
{
    return this.View();
}

So I'm not sure what's going on. I've searched around, and everything seems to suggest that it's either the machineKey changing (app cycles) or the user/session changing.

What else could be going on? How can I troubleshoot this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

完美的未来在梦里 2024-11-10 11:17:38

我不知道您是否意味着您能够按需获取错误 - 或者您在日志中看到它,但无论如何,这里有一种保证防伪令牌错误的方法。

等待...

  • 确保您已注销,然后输入您的登录信息
  • 双击登录按钮
  • 您将得到:

提供的防伪令牌适用于用户“”,但当前用户是“[电子邮件受保护]”。

(现在我假设这个确切的错误消息在 MVC4 中发生了变化,并且这基本上与您收到的消息相同)。

有很多人仍然双击所有内容 - 这很糟糕!我只是在醒来后才发现这一点,所以我真的不知道这是如何通过测试的。您甚至不必双击 - 如果按钮没有响应,当我第二次单击时,我自己就会遇到此错误。

我刚刚删除了验证属性。我的网站始终采用 SSL,我并不太担心风险。我现在只需要它就可以工作。另一种解决方案是使用 javascript 禁用该按钮。

这可以在 MVC4 初始安装模板上复制。

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 "[email protected]".

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

谜兔 2024-11-10 11:17:38

在 Adam 的帮助下,我将 MVC 源添加到我的项目中,并且能够看到有很多情况会导致相同的错误。

以下是用于验证防伪令牌的方法:

    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();
        }
    }

我的问题是将身份用户名与表单令牌的用户名进行比较的情况。就我而言,我没有设置用户名(一个为空,另一个为空字符串)。

虽然我怀疑很多人会遇到同样的情况,但希望其他人会发现看到正在检查的基本条件很有用。

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.

话少情深 2024-11-10 11:17:38

AntiForgeryToken 还会检查您登录的用户凭据是否已更改 - 这些凭据也在 cookie 中加密。您可以通过在 global.asax.cs 文件中设置 AntiForgeryConfig.SuppressIdentityHeuristicChecks = true 来关闭此功能。

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.

梦晓ヶ微光ヅ倾城 2024-11-10 11:17:38

您应该防止双重表单提交。
我使用如下代码来防止此类问题:

$('#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();
});

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

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'); 
});
诺曦 2024-11-10 11:17:38

您使用的是一台服务器还是网络农场?如果是单个服务器,请在 web.config 中注释掉 machineKey 元素,然后作为基本起点重试。有什么改变吗?
另外 - 您能想到您的 cookie 被清除或过期的任何原因吗 - 它们也是正常工作所必需的。

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.

夜访吸血鬼 2024-11-10 11:17:38

我刚刚遇到一个问题,@Html.AntiForgeryToken() 被调用两次,因此防伪造令牌在 HTTP Post 有效负载中被搞砸了。

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.

留一抹残留的笑 2024-11-10 11:17:38

在禁用提交按钮之前,有必要检查表单是否有效。

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

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');
    }
});

翻身的咸鱼 2024-11-10 11:17:38

另一件可能导致我出现此错误的事情是:我的一个表单中有两个 @Html.AntiForgeryToken()

一旦删除,问题就消失了。

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.

似最初 2024-11-10 11:17:38

当我必须将应用程序迁移到新机器时,我也遇到了同样的问题。我不明白为什么这个错误突然出现,但确信它与迁移有关,因此开始通过 aspnet_reqsql 调查数据库的注册,当这个错误被消除时,我意识到它一定与应用程序的注册有关果然我在类似的地方找到了答案。我在旅途中还发现有两种方法可以解决这个问题。

  1. ASP.NET 自动为每个应用程序生成一个加密密钥,并将该密钥存储在 HKCU 注册表配置单元中。当应用程序在服务器场上迁移或访问时,这些密钥不匹配,因此方法一是将唯一的计算机密钥添加到 web.config。机器密钥可以从 IIS 管理控制台生成并添加到 web.config 部分

  2. 第二种方法是使用 AspNet_RegIIS 和开关 -ga 通过 appPool 为工作进程授予对 HKCU 注册表的访问权限,或者使用 -i 为所有应用

aspnet_regiis -ga“IIS APPPOOL\应用程序池名称”

无论您选择哪种方法都应该解决此问题,但在我看来,未来迁移和服务器更改的最可靠方法将是 web.config 中的唯一密钥,请记住,这将导致应用程序覆盖 HKCU 注册表配置单元并保持应用程序运行。

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.

幽梦紫曦~ 2024-11-10 11:17:38

我刚刚遇到了类似的问题。我得到:

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

有趣的是,我尝试对其进行调试,并在两个地方看到了令牌,我希望在控制器中找到它

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

实际上,我应该一直在此处查看:

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

由于 Params 不仅仅包含表单字段,它还包含 QueryString 、表单、Cookie 和服务器变量。

一旦这个红鲱鱼消失,我发现 AntiForgeryToken 的形式错误!

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!

や莫失莫忘 2024-11-10 11:17:38

今天还点击了未提供所需的防伪令牌或无效。消息。

问题与 httpshttp 有关,实际的根本原因是我没有意识到我正在使用仅 http 配置启动 api 应用程序,而使用 https 启动 web-spa 。

希望这能帮助某人不要因为用户错误而浪费 4 个小时的生命

Also hit the A required anti-forgery token was not supplied or was invalid. message today.

Issue was related to https vs http and the actual root cause was me not realizing that i was starting the api-application using the http only configuration and the web-spa using https.

Hope this will help somebody to not waste 4 hours of lifetime because of a user-error

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文