RequestVerificationToken不匹配

vto*_*ola 34 security asp.net-mvc csrf antiforgerytoken asp.net-mvc-3

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

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

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

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

<input name="__RequestVerificationToken" type="hidden" value="QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2+ZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io/0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld">
Run Code Online (Sandbox Code Playgroud)

这是Cookie返回:

Set-Cookie:__RequestVerificationToken_L2VGbG93=skmTAVI8HCbfxDS+xhioIMIISL3UOBI7qJM1JbHjTtAqKl4W70pDUcTKMm0p3R3mrHDziE8vXw0C0OO4HArzWO1/e6py+v/cFdbe9maFgjl4jMiZ9Wc4YIhC6+IUXkk6yqJDJ8dCIr8qtGaYcD9IX+m7/SlVhu521KQSWJYRcaY=; path=/; HttpOnly
Run Code Online (Sandbox Code Playgroud)

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

__RequestVerificationToken:QK8P7rjyZE6Vm5seY7Fr704YCOoFGdTIMzl1W7R0ZFpXSMjGKLG2T05DfFSYTxvtQCEx7DDT69DGsDB2%2BZXFHY8oAjiKz0gw8BhDFywgmfIpoXnGpj7fONNzIIfvbrDrE9WJsMu6Io%2F0bDLM5WfKs0zktiNjyOWpfYrmnfINYmjW8NLOZFoz74xTcgTptAld
Run Code Online (Sandbox Code Playgroud)

区别在于两个出现编码的字符:

    /    ->   %2F  
    +    ->   %2B
Run Code Online (Sandbox Code Playgroud)

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

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

问候.

Sco*_*pey 77

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

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

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

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

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

如果这些都不适合你,那么我建议你看一下MVC的源代码ValidateAntiForgeryTokenAttribute,特别是OnAuthorization方法.它将帮助您查看验证失败的不同步骤.您甚至可以检查错误Exception.StackTrace以确定哪个部件出现故障.

作为旁注,我真的不喜欢ValidateAntiForgeryTokenMVC中的实现,因为:

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

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

  • 实际上,cookie和令牌总是不同的.cookie在请求之间保持不变,并且每次呈现时令牌都会更改.但是,它们始终解密为相同的值. (7认同)