asp.net-mvc 对防伪令牌问题进行故障排除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5767768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Troubleshooting anti-forgery token problems
提问by Jerad Rose
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:
这是 web.config 中的 machineKey:
<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:
我读过更改 HttpContext 上的用户将使令牌无效,但这不会发生在这里。我的 Join 操作上的 HttpGet 仅返回视图:
[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.
所以我不确定发生了什么。我四处搜索,似乎一切都表明它是 machineKey 更改(应用程序周期)或用户/会话更改。
What else could be going on? How can I troubleshoot this?
还有什么可能发生?我该如何解决这个问题?
采纳答案by Jerad Rose
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.
在 Adam 的帮助下,我将 MVC 源代码添加到我的项目中,并且能够看到有很多情况会导致相同的错误。
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.
虽然我怀疑很多人会遇到同样的情况,但希望其他人会发现查看正在检查的潜在条件很有用。
回答by Simon_Weaver
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]".
提供的防伪令牌适用于用户“”,但当前用户是“[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).
(现在我将假设这个确切的错误消息在 MVC4 中发生了变化,并且这基本上与您得到的消息相同)。
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.
我刚刚删除了验证属性。我的网站始终是 SSL,我并不太担心风险。我只需要它现在就可以工作。另一个解决方案是使用 javascript 禁用按钮。
This can be duplicated on the MVC4 initial install template.
这可以在 MVC4 初始安装模板上复制。
回答by VahidN
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 = truein the global.asax.cs file.
AntiForgeryToken 还会检查您的登录用户凭据是否已更改——这些凭据也在 cookie 中进行了加密。您可以通过AntiForgeryConfig.SuppressIdentityHeuristicChecks = true在 global.asax.cs 文件中设置来关闭它。
回答by Bohdan Lyzanets
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');
});
回答by Greg B
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.
我刚刚遇到了一个问题,@Html.AntiForgeryToken()即被调用了两次,因此反伪造令牌在 HTTP Post 负载中被搞砸了。
回答by Adam Tuliper - MSFT
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.
您是在一台服务器上还是在 Web 场上?如果是单个服务器,请在 web.config 中注释掉您的 machineKey 元素,然后再试一次作为基本起点。任何改变?另外 - 你能想到你的 cookie 被清除或过期的任何原因 - 它们也是正常工作所必需的。
回答by Pa?out
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');
}
});
回答by Graham Walker
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.
当我不得不将应用程序迁移到新机器时,我也遇到了同样的问题。不明白为什么会突然出现这个错误,但觉得肯定跟迁移有关系,于是开始通过aspnet_reqsql查数据库的注册问题,排除后发现肯定是应用注册的问题果然我在一个类似的地方找到了答案。我也在我的旅程中发现有两种方法可以解决这个问题。
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" />
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
ASP.NET 自动为每个应用程序生成一个加密密钥,并将密钥存储在 HKCU 注册表配置单元中。当应用程序在服务器场上迁移或访问时,这些密钥不匹配,因此方法一是向 web.config 添加唯一的机器密钥。机器密钥可以从 IIS 管理控制台生成并添加到您的 web.config 部分
的<machineKey的validationKey = “DEBE0EEF2A779A4CAAC54EA51B9ACCDED506DA2A4BEBA88FA23AD8E7399C4A8B93A006ACC1D7FEAEE56A5571B5AB6D74819CFADB522FEEB101B4D0F97F4E91” decryptionKey = “7B1EF067E9C561EC2F4695578295EDD5EC454F0F61DBFDDADC2900B01A53D4” 验证= “SHA1” 解密= “AES”/>
第二种方法是通过 appPool 使用 AspNet_RegIIS 和开关 -ga 或使用 -i 为所有应用程序授予对工作进程的 HKCU 注册表的访问权限
aspnet_regiis -ga "IIS APPPOOL\app-pool-name"
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.
无论您选择哪种方法都可以解决此问题,但在我看来,未来迁移和服务器更改的最可靠方法将是 web.config 中的唯一键,请记住,这将导致应用程序覆盖 HKCU 注册表hive 并保持应用程序运行。
回答by tony
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.
由于 Params 不仅仅包含表单字段,它还包含 QueryString、Form、Cookies 和 ServerVariables。
Once that red herring was out of the way I found the AntiForgeryToken was in the wrong form!
一旦那个红鲱鱼消失了,我发现 AntiForgeryToken 的形式有误!
回答by JensB
Another possible thing to check which has caused this error for me: I had two @Html.AntiForgeryToken()in one of my forms.
要检查的另一件事可能导致我出现此错误:我的@Html.AntiForgeryToken()一个表格中有两个。
Once that was removed problem went away.
一旦删除,问题就消失了。

