如何解决 ASP.Net MVC 应用程序中 iisreset 后发生的 AntiForgeryToken 异常?
我在 ASP.Net MVC 中遇到 AntiForgeryToken 问题。如果我在我的 Web 服务器上执行 iisreset 并且用户继续其会话,他们会跳到登录页面。并不可怕,但是 AntiForgery 令牌会爆炸,再次启动的唯一方法就是炸掉浏览器上的 cookie。
在版本 1 的测试版中,当我读回 cookie 时,它常常会出错,所以我过去常常在请求验证令牌之前清理它,但在发布时这个问题得到了修复。
现在我想我会回滚到修复测试版问题的代码,但我忍不住认为我错过了一些东西。有没有更简单的解决方案,我应该放弃他们的助手并从头开始创建一个新的吗?我感觉很多问题是因为它与旧的 ASP.Net 管道紧密相连,并试图将其拼凑起来,去做一些它本来不是设计要做的事情。
我查看了 ASP.Net MVC 2 RC 的源代码,看起来代码没有太大变化,所以虽然我没有尝试过,但我认为那里没有任何答案。
这是异常堆栈跟踪的相关部分。
编辑:我刚刚意识到我没有提到这只是尝试在 GET 请求上插入令牌。这不是您执行 POST 启动时发生的验证。
System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not
supplied or was invalid.
---> System.Web.HttpException: Validation of viewstate MAC failed. If this
application is hosted by a Web Farm or cluster, ensure that <machineKey>
configuration specifies the same validationKey and validation algorithm.
AutoGenerate cannot be used in a cluster.
---> System.Web.UI.ViewStateException: Invalid viewstate.
Client IP: 127.0.0.1
Port: 4991
User-Agent: scrubbed
ViewState: scrubbed
Referer: blah
Path: /oursite/Account/Login
---> System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError)
at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
--- End of inner exception stack trace ---
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path)
at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path)
I’m having problems with the AntiForgeryToken in ASP.Net MVC. If I do an iisreset on my web server and a user continues with their session they get bounced to a login page. Not terrible but then the AntiForgery token blows up and the only way to get going again is to blow away the cookie on the browser.
With the beta version of version 1 it used to go wrong when reading the cookie back in for me so I used to scrub it before asking for a validation token but that was fixed when it was released.
For now I think I’ll roll back to my code that fixed the beta problem but I can’t help but think I’m missing something. Is there a simpler solution, heck should I just drop their helper and create a new one from scratch? I get the feeling that a lot of the problem is the fact that it’s tied so deeply into the old ASP.Net pipeline and is trying to kludge it into doing something it wasn’t really designed to do.
I had a look in the source code for the ASP.Net MVC 2 RC and it doesn't look like the code has changed much so while I haven't tried it, I don't think there are any answers there.
Here is the relevant part of the stack trace of the exception.
Edit: I just realised I didn't mention that this is just trying to insert the token on the GET request. This isn't the validation that occurs when you do a POST kicking off.
System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not
supplied or was invalid.
---> System.Web.HttpException: Validation of viewstate MAC failed. If this
application is hosted by a Web Farm or cluster, ensure that <machineKey>
configuration specifies the same validationKey and validation algorithm.
AutoGenerate cannot be used in a cluster.
---> System.Web.UI.ViewStateException: Invalid viewstate.
Client IP: 127.0.0.1
Port: 4991
User-Agent: scrubbed
ViewState: scrubbed
Referer: blah
Path: /oursite/Account/Login
---> System.Security.Cryptography.CryptographicException: Padding is invalid and
cannot be removed.
at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError)
at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
--- End of inner exception stack trace ---
at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path)
at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
现在我已经采用了一个解决方案,如果抛出异常,则会擦除 cookie。如果再次抛出异常,我将让它按原样发生。
我暂时不会将此标记为“最佳”答案,希望有人能有更好的答案。
For now I've gone with a solution that scrubs the cookie if the exception is thrown. If the exception is thrown again I'll just let it happen as it was.
I won't mark this as 'the' answer for now in the hope that someone has a better answer.
我遇到了这个问题,要解决这个问题,您需要做的就是在您的网络配置中添加一个显式的机器密钥...
确保将其放置在 web.config 中...
i had this issue and to fix what you need to do is add an explicit machine key in your web-config...
ensure its placed in web.config within...
您可以将
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
添加到global.asax
You can add
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
intoglobal.asax
iisreset 没有理由将用户带到登录页面。如果您使用 cookie 来跟踪身份验证信息并拥有无状态应用程序,则即使在服务器重新启动后,用户也应该保持身份验证(当然,如果在重置期间发出请求,则会失败)。
There's no reason an iisreset to bring the user to the login page. If you use cookies to track authentication information and have a stateless application, the user should stay authenticated even after a server reboot (of course if a request is made during the reset it will fail).
实际上,我发现这在我的登录操作中起作用:
重要的部分是:Response.Cookies.Clear();
Actually I found this to work in my logon action:
The important part was : Response.Cookies.Clear();
如果您的 MachineKey 设置为AutoGenerate,那么您的验证令牌等将无法在应用程序重新启动后继续存在 - ASP.NET 将在启动时生成一个新密钥,然后将无法正确解密令牌。
如果您经常看到这种情况,我建议:
1 实现此目的的最佳方法是使用负载平衡应用程序,这将要求您设置静态 MachineKey。另一种选择是通过在网站的根目录中放置一个名为
app_offline.htm
的文件来关闭网站,这将使网站脱机并显示您的消息 - 至少用户会期望一切正常错误的。If your MachineKey is set to AutoGenerate, then your verification tokens, etc won't survive an application restart - ASP.NET will generate a new key when it starts up, and then won't be able to decrypt the tokens correctly.
If you are seeing this a lot, I'd suggest:
1 The best way to do this is by having a loadbalanced application, which will require you to set a static MachineKey. Another option is to take the site down by placing a file named
app_offline.htm
in the root of the site, which will take the site offline and display your message - at least the users will expect things to go wrong.