RequestVerificationToken不匹配

我有一个反CRSF MVC机制的问题。 返回的cookie和表单input不匹配。 我每次都收到一个错误,只能在一个特定的页面。 在其余的应用程序中,它运作良好。

服务器正在返回HTTP 500 Internal Server Error ,我可以在日志中看到这个exception:

[System.Web.Mvc.HttpAntiForgeryException]:{“所需的防伪标记未提供或无效。”}

这是服务器正在生成的隐藏input是:

 <input name="__RequestVerificationToken" type="hidden" value="QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2+ZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io/0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld"> 

这是返回的Cookie:

 Set-Cookie:__RequestVerificationToken_L2VGbG93=skmTAVI8HCbfxDS+xhioIMIISL3UOBI7qJM1JbHjTtAqKl4W70pDUcTKMm0p3R3mrHDziE8vXw0C0OO4HArzWO1/e6py+v/cFdbe9maFgjl4jMiZ9Wc4YIhC6+IUXkk6yqJDJ8dCIr8qtGaYcD9IX+m7/SlVhu521KQSWJYRcaY=; path=/; HttpOnly 

当我检查服务器发送的内容时,cookie是完全一样的,但是我认为有效载荷有不同的编码:

 __RequestVerificationToken:QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2%2BZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io%2F0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld 

差异是以两个字符显示编码:

  / -> %2F + -> %2B 

这些是我可以find隐藏的input字段和后有效载荷之间唯一的区别。

可能是导致ValidateAntiForgeryTokenvalidation令牌失败的问题?

问候。

我最近用ValidateAntiForgeryToken解决了几个问题,所以我会和你分享我的发现。

:既然你提到这只发生在一个页面上,我最好的猜测是你在调用Html.AntiForgeryToken(salt)ValidateAntiForgeryToken(salt)调用时使用不同的salt值。

AJAX :正如另一个答案所说,使用AJAX可能需要额外的工作来确保令牌包含在POST中。 这是我最喜欢的简单的自动解决scheme,将令牌添加到所有AJAX POST请求 。
在你的问题,但你说,你已经validation令牌正在发送。 你是否证实你只发送一次令牌? 我发现我的一个AJAX调用发送了令牌两次,这些值组合在一起,导致它失败。

机器键和cookies :这个问题是丑陋的,容易发现(导致exception),但不是很直观。 validationcookie和令牌使用唯一的“机器密钥”进行编码和解码。 这意味着如果您有一个服务器场,或更改您的服务器,您的cookie将不再有效。 closures浏览器可以解决问题(因为cookie是一个会话cookie)。 但是,有些人在后台打开浏览器窗口已经很久了!
解决办法是在你的configuration文件中设置一个“机器密钥”。 这将告诉MVC在所有服务器上使用相同的密钥,确保cookie在任何地方都可以被解密。

编码错误 :使用名为jMeter的testing工具,我们试图加载testing我们的页面,只是发现它有一个错误,导致我们的令牌有两个额外的值“。
解决方法是降低对工具的信任度! 在浏览器中testing,如果可行,创build一个提取token和cookie值的testing,并设置一个断点来validation结果。

如果这些东西都不适合你,那么我build议看看MVC源代码的ValidateAntiForgeryTokenAttribute ,特别是OnAuthorization方法。 这将帮助您看到validation失败的不同步骤。 你甚至可以检查你的错误的Exception.StackTrace以确定哪个部分失败。

作为一个方面说明 ,我真的不喜欢MVC中的ValidateAntiForgeryToken的实现,因为:

  • 大约有5个validation步骤可能会失败,但只有一个通用错误消息。
  • 该类是密封的,所以它不能扩展与额外的function。
  • encryption方法很奇怪 – 它初始化Page并创build一个虚拟的ViewState来encryption令牌和cookie。 似乎矫枉过正

所以,我抓住了源代码,并创build了自己的专用子类,这也对debugging问题非常有帮助,因为我可以在validation方法上设置断点,并且确定哪个validation步骤失败。

如果这是作为Ajax请求发送的,那么框架的当前设置不会自然而然地被构build。

幸运的是,Phil Haak在处理CSRF和Ajax方面写了一篇很好的博客文章 – > 使用Ajax预防CSRF ,其中详细介绍了如何使用现有的框架并将其修改为适用于Ajax / Json。

从我最近的发现…

如果您在ajax请求中将内容types设置为“application / x-www-form-urlencoded”,那么您必须将AFRT放入数据

如果你将内容types设置为“application / json”,那么令牌就像hack所描述的那样进入ajax“headers”属性。

在服务器上,如果你正在检查表单types令牌,那么使用vanilla AntiForgeryRequestTokenAttribute是可以的,但是如果你想validation在头文件中发送的令牌,那么你需要调用AntiForgeryToken.OnAuthorize …或者其他任何东西, cookie(http上下文)。

这不容易,但如果这是每个人都会这样做:)