我一直在浏览一个开发项目的错误日志,发现以下错误(更改名称以保护有罪的无辜者)-
提供的防伪令牌用于用户“”,但当前用户是“管理员”。
这不是一个特别难以重现的问题-
- 在登录页面打开应用程序
- 在登录之前,在同一台计算机上的同一浏览器中打开第二个窗口或选项卡到登录页面
- 在第一个窗口中登录(或者实际上是第二个,顺序无关紧要)
- 尝试在剩余的登录窗口中登录
堆栈跟踪是-
System.Web.Mvc.HttpAntiForgeryException (0x80004005):提供的防伪令牌用于用户“”,但当前用户是“管理员”。在 System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase httpContext) 在 System.Web.Helpers.AntiForgeryWorker.Validate(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken) 在 System.Web.Helpers.AntiForgery。 Validate() 在 System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext filterContext) 在 System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 过滤器, ActionDescriptor actionDescriptor) 在 System.Web.Mvc.Async.AsyncControllerActionInvoker。 <>c__DisplayClass25.
登录方法签名是-
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
...
}
这与互联网“ASP.NET MVC 4 Web 应用程序”模板项目中的方法签名完全相同,这表明微软要么认为 ValidateAntiForgeryToken 是必要的/最佳实践,要么只是在此处添加了该属性,因为它已被使用其他地方。
显然,我无法在此方法中处理该问题,因为它没有达到,ValidateAntiForgeryToken 是一个预请求过滤器,它在请求到达控制器之前阻止它。
我可以在提交表单之前检查用户是否通过 Ajax 进行了身份验证,如果是,则尝试重定向到他们,或者只是删除该属性。
问题是这样的-我知道令牌的设计目的是在用户已经针对您的站点进行身份验证时阻止来自另一个站点 (CSRF) 的请求,因此在此基础上从定义将使用的表单中删除它是一个问题未经身份验证的用户?
据推测,此实例中的属性旨在减轻恶意行为者为您的应用程序提供虚假登录表单的风险(尽管在抛出异常时可能用户已经输入了他或她将被记录的详细信息 - 但它可能会提醒他们一些事情是错的)。否则,从外部站点向表单提交不正确的凭据肯定会导致与站点本身完全相同的结果吗?我不依赖客户端验证/清理来清理潜在的不安全输入。
其他开发人员是否遇到过这个问题(或者我们是否有非常有创意的用户),如果是这样,您是如何解决/缓解它的?
更新:这个问题在 MVC5 中仍然存在,完全是故意的,现在出现错误消息“提供的防伪令牌是针对与当前用户不同的基于声明的用户。” 使用默认模板和身份提供程序时。Microsoft Developer Evangelist 和 Troy 的 PluralSight 同事 Adam Tuliper 在登录页面上的 Anti forgery token 上提供了一个相关的问题和有趣的答案,建议只需删除该令牌。