MVC3 AntiForgeryToken问题

时间:2011-08-29 18:03:39

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

我正在尝试为我的MVC3应用程序实现AntiForgeryToken。设置FormAuthentication cookie后,我遇到了AntiForgeryToken的问题。这是一个简单的例子,它解释了我的问题。

我有家庭控制器,有以下行动方法:

public class HomeController : Controller
{
    public ActionResult Logon()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Logon(string userName, string password)
    {
        FormsAuthentication.SetAuthCookie(userName, false);
        return View("About");
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult About(FormCollection form)
    {
        return View("PageA");
    }
 }

这是我的登录和关于视图:

Logon.cshtml:

   @using (Html.BeginForm("Logon", "Home"))
   {

    @Html.AntiForgeryToken()

    <label> UserName :</label>
    <input  name = "userName" type="text"/>
    <br />
    <label> Password :</label>
    <input name = "password" type="password"/>
    <br />
    <br />
    <input type="submit" value="LogOn" />

   }

About.cshtml

@using (Html.BeginForm("About", "Home"))
{

    @Html.AntiForgeryToken()
    <p> This is conent of page About</p>
    <input  name = "moreInfo" type="text"/>

    <input type="submit" value="SubmitAbout" />
}

我对“登录”帖子方法没有任何问题。它正在验证antiforgerytoken和渲染About视图。有趣的是,当我在“关于”视图上发帖时,我收到错误“未提供所需的防伪标记或无效”

有人可以指出我在这里做错了吗?

感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

我做了一些测试,并确定即使您致电FormsAuthentication.SetAuthCookie(...),问题仍然是httpContext.User.Identity.Name在请求期间仍然为空。

因此,要解决此问题,您需要手动设置当前User

FormsAuthentication.SetAuthCookie(email, true);
this.HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null);

这将设置调用User时使用的正确Html.AntiForgeryToken()

请注意,普通PRG模式网站不需要此代码,因为重定向后,将加载正确的User

此外,由于您的Logon方法需要有效的用户名和密码,因此它不太容易受到CSRF攻击,因此您可能不需要在该方法上使用ValidateAntiForgeryToken。也许这就是AntiForgeryToken依赖于用户名的原因。 CSRF攻击通常只利用已经过身份验证的用户。

答案 1 :(得分:2)

我似乎记得,一旦您登录您的令牌现在与您的用户名不同,我相信会更改此令牌,因此将不再有效。我会试着仔细检查一下,但几乎可以肯定我过去遇到了这个问题。

但是,在上面的代码中,如果使用此模式,则会遇到其他问题。除非出现异常/验证错误并且您正在重新显示页面,否则后期操作通常不会显示视图。通常你会重定向。我看到有人在上面的评论中触及了这一点,他们是正确的。

这并不意味着您不应该使用这些操作,但要注意通过登录进行此操作。此前帖提到使用带令牌的用户名:

Troubleshooting anti-forgery token problems


public void Validate(HttpContextBase context, string salt) {
        Debug.Assert(context != null);

        string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);

        HttpCookie cookie = context.Request.Cookies[cookieName];
        if (cookie == null || String.IsNullOrEmpty(cookie.Value)) {
            // error: cookie token is missing
            throw CreateValidationException();
        }
        AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value);

        string formValue = context.Request.Form[fieldName];
        if (String.IsNullOrEmpty(formValue)) {
            // error: form token is missing
            throw CreateValidationException();
        }
        AntiForgeryData formToken = Serializer.Deserialize(formValue);

        if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) {
            // error: form token does not match cookie token
            throw CreateValidationException();
        }

        string currentUsername = AntiForgeryData.GetUsername(context.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();
        }

        if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) {
            // error: custom validation failed
            throw CreateValidationException();
        }
    }


答案 2 :(得分:2)

如果请求中存在具有相同名称的cookie,则AntiForgeryToken Helper不会向响应中添加任何cookie。此外,AntiForgeryToken Helper使用Principal.Identity.Name返回隐藏字段的值。

            AntiForgeryData formToken = new AntiForgeryData(cookieToken) {
               Salt = salt,
               Username = AntiForgeryData.GetUsername(httpContext.User)
            };

因此,当您的Login视图使用Html.AntiForgeryToken时,会在响应时设置一个新cookie,并在隐藏字段中设置相同的值。当您的Login视图使用隐藏字段发布此cookie时,不会抛出任何异常,因为请求cookie和隐藏字段值都匹配。但是在About视图的情况下,不会在响应中添加额外的cookie,但由于IIdentty,将为helper返回一个新的隐藏值。因此,当您发布“关于”操作时,将引发异常,因为cookie和隐藏值不匹配。

这可能是AntiForgeryToken实施中的错误。

相关问题