Asp.net mvc MVC3反伪造代币问题

Asp.net mvc MVC3反伪造代币问题,asp.net-mvc,asp.net-mvc-3,antiforgerytoken,Asp.net Mvc,Asp.net Mvc 3,Antiforgerytoken,我正在尝试为我的MVC3应用程序实现AntiForgeryToken。设置FormAuthentication cookie后,我遇到AntiForgeryToken问题。这里有一个简单的例子来解释我的问题 我有一个具有以下操作方法的主控制器: public class HomeController : Controller { public ActionResult Logon() { return View(); } [HttpPost]

我正在尝试为我的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" />

   }
@使用(Html.BeginForm(“登录”、“主页”))
{
@Html.AntiForgeryToken()
用户名:

密码:

}
关于.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" />
}
@使用(Html.BeginForm(“关于”,“家”))
{
@Html.AntiForgeryToken()
这是第页的内容

}
我对“登录”post方法没有问题。它正在验证antiforgerytoken并呈现有关视图的信息。有趣的是,当我在“关于”视图上发布“我收到错误”时,所需的防伪令牌未提供或无效

有人能指出我做错了什么吗


感谢您的帮助。

我似乎记得,一旦您登录,您的令牌现在已不同,因为您的用户名已更改此令牌,因此不再有效。我会再检查一遍,但几乎可以肯定我以前遇到过这种情况

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

但这并不意味着你不应该使用这些操作,但要小心在登录时忽略这些操作。这篇之前的文章暗示了用户名与令牌的使用:


我似乎记得,一旦你登录你的令牌现在是不同的,因为你的用户名我相信改变了这个令牌,因此将不再有效。我会再检查一遍,但几乎可以肯定我以前遇到过这种情况

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

但这并不意味着你不应该使用这些操作,但要小心在登录时忽略这些操作。这篇之前的文章暗示了用户名与令牌的使用:


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

            AntiForgeryData formToken = new AntiForgeryData(cookieToken) {
               Salt = salt,
               Username = AntiForgeryData.GetUsername(httpContext.User)
            };
因此,当您的登录视图使用Html.AntiForgeryToken时,将在响应和具有相同值的隐藏字段上设置一个新cookie。当您的登录视图使用隐藏字段发布此cookie时,不会引发异常,因为请求cookie和隐藏字段值都匹配。但是在About视图的情况下,不会向响应中添加额外的cookie,但是由于IIdentty,将为helper返回一个新的隐藏值。所以,当您发布关于操作的帖子时,将引发异常,因为cookie和隐藏值不匹配


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

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

            AntiForgeryData formToken = new AntiForgeryData(cookieToken) {
               Salt = salt,
               Username = AntiForgeryData.GetUsername(httpContext.User)
            };
因此,当您的登录视图使用Html.AntiForgeryToken时,将在响应和具有相同值的隐藏字段上设置一个新cookie。当您的登录视图使用隐藏字段发布此cookie时,不会引发异常,因为请求cookie和隐藏字段值都匹配。但是在About视图的情况下,不会向响应中添加额外的cookie,但是由于IIdentty,将为helper返回一个新的隐藏值。所以,当您发布关于操作的帖子时,将引发异常,因为cookie和隐藏值不匹配


这可能是AntiForgeryToken实现中的一个错误。

我做了一些测试,并确定即使在调用
FormsAuthentication.SetAuthCookie(…)
之后,
httpContext.User.Identity.Name在请求期间仍然为空

因此,要解决此问题,您需要手动将当前
用户设置为:

FormsAuthentication.SetAuthCookie(email, true);
this.HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null);
这将设置调用
Html.AntiForgeryToken()
时使用的正确的
用户

请注意,对于正常的PRG模式网站,此代码不是必需的,因为在重定向之后,将加载正确的
用户


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

我做了一些测试,并确定即使在调用
FormsAuthentication.SetAuthCookie(…)
之后,问题是
httpContext.User.Identity.Name在请求期间仍然为空

因此,要解决此问题,您需要手动将当前
用户设置为:

FormsAuthentication.SetAuthCookie(email, true);
this.HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null);
这将设置调用
Html.AntiForgeryToken()
时使用的正确的
用户

请注意,对于正常的PRG模式网站,此代码不是必需的,因为在重定向之后,将加载正确的
用户

另外,由于您的
Logon
方法需要有效的用户名和密码,因此它实际上不易受到CSRF攻击,因此您可能不需要在该方法上使用
ValidateAntiForgeryToken
。也许这就是为什么AntiForgeryToken依赖于用户名。CSRF攻击通常是