RequestVerificationToken不匹配

时间:2011-10-14 11:31:33

标签: asp.net-mvc asp.net-mvc-3 security csrf antiforgerytoken

我遇到了反CRSF MVC机制的问题。 cookie和返回的表单输入不匹配。我每次都会收到一个错误,只在一个特定的页面中。在应用程序的其余部分,它运行良好。

服务器正在返回HTTP 500 Internal Server Error,我可以在日志中看到此异常:

  

[System.Web.Mvc.HttpAntiForgeryException]:{“必需的防伪   令牌未提供或无效。“}

这是服务器生成的隐藏输入:

<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

这是我在隐藏输入字段和post有效负载之间可以找到的唯一差异。

导致ValidateAntiForgeryToken验证令牌失败的问题是什么?

问候。

3 个答案:

答案 0 :(得分:77)

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

Salt :由于您提到这只发生在一个页面上,我最好的猜测是您在调用salt和{{Html.AntiForgeryToken(salt)时使用了不同的ValidateAntiForgeryToken(salt)值1}}来电。

AJAX :正如另一个答案所说,使用AJAX可能需要额外的工作来确保令牌包含在POST中。这是我最喜欢的simple, automatic solution to add the token to all AJAX POST requests 但是,在您的问题中,您声明您已验证令牌正在发送。您是否确认过您只发送一次令牌?我发现我的一个AJAX调用正在发送令牌两次,这两个值组合在一起,导致它失败。

机器密钥和Cookie :这个问题很难看,容易发现(导致异常),但不是很直观。验证cookie和令牌使用唯一的“机器密钥”进行编码和解码。这意味着,如果您有服务器场或更改服务器,则您的cookie将不再有效。关闭浏览器可以解决问题(因为cookie是会话cookie)。但是,有些人长时间在后台打开浏览器窗口! 解决方案是在配置文件中设置“机器密钥”。这将告诉MVC在所有服务器上使用相同的密钥,确保cookie在任何地方都可以解密。

编码错误:使用名为jMeter的测试实用程序,我们尝试对页面进行加载测试,但发现它有一个错误导致我们的令牌有2个{{1}围绕价值。
解决方案是降低您对工具的信任!在浏览器中进行测试,如果可行,则创建一个提取令牌和cookie值的测试,并设置断点以验证结果。

如果这些内容都不适合您,那么我建议您查看the MVC source code for ValidateAntiForgeryTokenAttribute,特别是"方法。它将帮助您查看验证失败的不同步骤。您甚至可以检查错误OnAuthorization以确定哪个部分失败。

作为旁注,我真的不喜欢MVC中Exception.StackTrace的实现,因为:

  • 大约有5个验证步骤可能会失败,但只有一条通用错误消息。
  • 该类已密封,因此无法使用其他功能进行扩展。
  • 加密方法很奇怪 - 它初始化ValidateAntiForgeryToken并创建一个人工Page来加密令牌和cookie。似乎过度杀伤。

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

答案 1 :(得分:4)

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

幸运的是Phil Haak写了一篇关于处理CSRF和Ajax的好文章 - &gt; Preventing CSRF With Ajax详细介绍了如何使用现有框架并对其进行修改以适用于Ajax / Json。

答案 2 :(得分:2)

根据我最近的调查结果......

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

如果您将内容类型设置为“application / json”,则令牌会进入ajax“headers”属性,如haack所述。

在服务器上,如果您正在检查表单类型令牌,那么使用vanilla AntiForgeryRequestTokenAttribute是正常的,但如果您想验证在标头中发送的令牌,那么您需要调用AntiForgeryToken.OnAuthorize ...或者其他任何内容,传递来自cookie的令牌(http上下文)。

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