覆盖登录页面上的防伪令牌错误

6
我有一个网站,它经常会出现以下大量错误:
提供的防伪标记是针对与当前用户不同的基于声明的用户。
防伪Cookie标记和表单字段标记不匹配。
例如,在登录页面上防伪标记是为 no user 而不是当前用户,但包含了用户,我希望能够防止该网站在此情况下抛出错误:
提供的防伪标记是针对用户“”,但当前用户是“Garret”。
我不希望这个异常适用于除登录页面之外的任何其他页面。因此,我不想将 AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; 添加到整个网站。同时,由于该网站包含HIPAA数据,我想尽可能保持其安全性。那么,在保证尽可能安全的前提下,如何才能尝试在登录页面上防止此错误呢,因为它使用户难以使用?
该网站托管在负载均衡服务器上,但我认为这并不是问题所在。我认为该错误主要是由于使用浏览器的后退按钮、在登陆之前打开登陆页面,已经登录或多次点击登录按钮造成的。还有一些用户通过应用程序访问该网站,可能没有加载该页面,而只是尝试发布登录信息。
请告诉我,在尽可能保证安全的同时,防止登录页面上出现此错误的最佳选项是什么?
4个回答

4
我最终采取的措施,似乎在保证相同安全性的同时起到了作用,就是在检查用户是否已登录后手动检查防伪令牌。
    [HttpPost]
    [AllowAnonymous]
    //[ValidateAntiForgeryToken]
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        // Skip the login process if the user is already logged in
        if (User.Identity.IsAuthenticated) 
        {
            return RedirectToAction("Index", "Home");
        }
        // Check the anti forgery token now
        System.Web.Helpers.AntiForgery.Validate();
        ...

看起来明智的做法是检查当前已验证的用户是否与您尝试登录的用户匹配,以便如果用户共享计算机,则用户不会获得对孤立会话的访问权限。 - Kaizen Programmer

2

针对某些用户发起的并发登录尝试,有一个解决方案:

如何解决“AntiForgery Token是为用户""而设计的,但当前用户是"xxxx"”错误

如果用户在填写登录页面时用了太长时间,导致出现AntiForgeryToken异常,则简单地将其重定向到该页面,并显示一条消息,说明他/她的会话(即安全令牌)已过期。

[HttpPost]
[ValidateAntiForgeryToken]
[HandleError(View="Login", ExceptionType = typeof(HttpAntiForgeryException))]
public ActionResult Login(LoginModel model)
{
     // some login processing stuff
}

如果异常是由用户点击后退按钮引起的,在客户端提供JS函数,仅在登录页面上防止后退按钮操作。请注意保留HTML标签。
<body onload="window.history.forward()">...</body>

// or wrap it inside a function
<script type="text/javascript">
function noBackOnLogin() {
        window.history.forward();
        history.pushState(null, document.title, url); // if you want to include Mobile Safari, see https://dev59.com/q2ct5IYBdhLWcg3wD5WU#34337617
    }
</script>
<body onload="noBackOnLogin();" onpageshow="if (event.persisted) noBackOnLogin();">...</body>

对于已经登录的某个用户,将其重定向到主页或其他页面,并显示他们的用户名(使用User.Identity.Name)。

希望这个解释有用。


谢谢你的快速回答,我还没有测试的机会,但是当我测试后,如果它有效,我会回来报告并标记为已接受。 - Garrett Fogerlie

1

我使用自定义属性来处理异常并将用户重定向到主页,而不是检查User.Identity.IsAuthenticated。

我相信这避免了使用其他方法可能存在的任何安全问题。

public override void OnException(ExceptionContext filterContext)
    {
        var controllerName = (string)filterContext.RouteData.Values["controller"];
        var actionName = (string)filterContext.RouteData.Values["action"];
        var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        if (filterContext.Exception is HttpAntiForgeryException)
        {
            filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary
                {
                    { "action", "Index" },
                    { "controller", "Home" }
                });

            filterContext.ExceptionHandled = true;
        }
}

0
回答 @Michael_B 的疑虑,你可以尝试修改 Garrett 解决方案中的这一部分:
    // Skip the login process if the user is already logged in
    if (User.Identity.IsAuthenticated) 
    {
        return RedirectToAction("Index", "Home");
    }
    // Check the anti forgery token now
    System.Web.Helpers.AntiForgery.Validate();
    ...

转换为:

    // if not authenticated, check anti forgery token now:
    if (!User.Identity.IsAuthenticated) 
    {
        System.Web.Helpers.AntiForgery.Validate();
    }
    // run rest of login process normally

    ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接