MVC ValidateAntiForgeryToken multi-tabs problem

☆樱花仙子☆ 提交于 2020-01-01 03:21:10

问题


We'd been getting "A required anti-forgery token was not supplied or was invalid." errors, and on some further investigation, I've managed to recreate the problem in its simplest form - i'm either doing something completely wrong, or this is a limitation of the anti-forgery token system.

Either way, I'd appreciate some advice!

Empty MVC 2 project: one view page, one controller

view:

<%--Sign in form:--%>
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken()%>
    <input type="submit" value="Sign in" />
<%}%>

Controller:

public ActionResult Index()
{
    ViewData["status"] = "Index";
    return View();
}

[ValidateAntiForgeryToken]
public ActionResult SignIn()
{
    ViewData["status"] = "Signed In!";
    FormsAuthentication.SetAuthCookie("username", false);
    return View("Index");
}

[EDIT: simplified code example]

In order to recreate the exception, open two non-signed-in tabs - sign-in on the first tab, and then sign-in on the second tab.

The second tab will always throw an anti-forgery exception, when I guess correct behaviour would be to redirect to the signed-in page (sharing the session/authentication of the original signed-in tab)

Any advice would be appreciated!

Cheers, Dave


回答1:


Looking at the MVC 2 source code it looks like the AntiForgeryToken hidden field includes the User.Identity.Name serialized, if your signed in. In line 69 of the ValidateAntiForgeryTokenAttribute it seems to then check your token with the current User.Identity.Name.

    string currentUsername = AntiForgeryData.GetUsername(filterContext.HttpContext.User);
    if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
        // error: form token is not valid for this user
        // (don't care about cookie token)
        throw CreateValidationException();
    }

Because in your other tab you are now signed in the code above invalidates the existing token which doesn't contain the User.Identity.Name.

This could be fixed by adding a !string.IsNullOrEmpty(formToken.Username) around that check but I don't know if that will open up security issues plus it means having a custom MVC 2 Build.




回答2:


You could use the same salt:

<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken("123")%>
    <input type="submit" value="Sign in" />
<%}%>

<% using(Html.BeginForm("Protected", "Home", FormMethod.Post)) {%>
    <%= Html.AntiForgeryToken("456")%>
    <input type="submit" value="Do secret stuff" />
<%}%>

And in your controller:

[ValidateAntiForgeryToken(Salt = "123")]
public ActionResult SignIn()
{
    ViewData["status"] = "Signed In!";
    FormsAuthentication.SetAuthCookie("username", false);
    return View("Index");
}

[Authorize]
[ValidateAntiForgeryToken(Salt = "456")]
public ActionResult Protected()
{
    ViewData["status"] = "Authed";
    return View("Index");
}

Do the same with the other token but make sure to pick a different salt.




回答3:


The real answer to this problem is simply that you shouldn't use an anti-forgery token on login forms!

It's pointless to "forge" being a user on a login form - they aren't logged in!



来源:https://stackoverflow.com/questions/4031617/mvc-validateantiforgerytoken-multi-tabs-problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!