登录后AntiForgeryToken无效

Mar*_*tin 13 asp.net-mvc antiforgerytoken csrf-protection asp.net-mvc-3

我有一个用户无需登录即可发布的表单.但是,如果他的电子邮件被识别,则需要输入密码.密码表单通过Ajax验证,如果成功,则提交主表单.两种形式都需要有效的AntiForgeryToken.

问题是,密码检查作为副产品也签署了用户(来自客户的要求).这使令牌无效,并且无法发送主表单.

我已尝试以编程方式生成新令牌,但我无法让它工作.

关于如何解决这个问题的任何想法?

最终解决方案

我发现这个问题有助于输入反射.但是,这就是为什么在正常情况下你会避免黑客攻击内部类型的主要原因,这些类型是在版本之间的程序集之间进行的.正如贝蒂建议的那样,使用ILSpy来寻找东西.

这是最终的代码.

if (signIn)
    FormsAuth.SignIn(user.Email, false);


var mvcAssembly = typeof(AntiForgery).Assembly;
var afdType = mvcAssembly.GetType("System.Web.Helpers.AntiForgeryData");
string fieldName = Convert.ToString(afdType.InvokeMember(
    "GetAntiForgeryTokenName",
    BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
    null,
    null,
    new object[] { null }));

var serializerType = mvcAssembly.GetType("System.Web.Helpers.AntiForgeryDataSerializer");
var serializerCtor = serializerType.GetConstructor(new Type[0]);
object serializer = serializerCtor.Invoke(new object[0]);


string text = HttpContext.Request.Form[fieldName];
object antiForgeryData = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { text });

afdType.GetProperty("Username").SetValue(antiForgeryData, 
    signIn ? user.Email : string.Empty, 
    null);

string newToken = Convert.ToString(serializerType.InvokeMember(
    "Serialize",
    BindingFlags.InvokeMethod,
    null,
    serializer,
    new object[] { antiForgeryData }));

return Content(JsonConvert.SerializeObject(new
                                                {
                                                    success = true,
                                                    newAntiForgeryToken = newToken
                                                }), Constant.JsonContentType);
Run Code Online (Sandbox Code Playgroud)

升级WebPages 2.0

  var mvcAssembly = typeof(AntiForgery).Assembly;
        var afdType = mvcAssembly.GetType("System.Web.Helpers.AntiXsrf.AntiForgeryToken");
        //string fieldName = Convert.ToString(afdType.InvokeMember(
        //    "GetAntiForgeryTokenName",
        //    BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
        //    null,
        //    null,
        //    new object[] { null }));

        string fieldName = "__RequestVerificationToken";

        var serializerType = mvcAssembly.GetType("System.Web.Helpers.AntiXsrf.AntiForgeryTokenSerializer");
        var serializerCtor = serializerType.GetConstructor(new Type[0]);
        object serializer = serializerCtor.Invoke(new object[0]);


        string text = HttpContext.Request.Form[fieldName];
        string newToken = String.Empty;

        if (!String.IsNullOrEmpty(text))
        {
            object antiForgeryToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null,
                                                                 serializer, new object[] { text });

            afdType.GetProperty("Username").SetValue(antiForgeryToken,
                                                     signIn ? user.Email : string.Empty,
                                                     null);

            newToken = Convert.ToString(serializerType.InvokeMember(
                "Serialize",
                BindingFlags.InvokeMethod,
                null,
                serializer,
                new[] { antiForgeryToken }));
        }
Run Code Online (Sandbox Code Playgroud)

Bet*_*tty 4

当前用户存储在表单数据的防伪令牌中,并在回发时与当前用户进行比较。

您应该能够在回发时提取表单令牌,就像 Phil Haack 在这篇文章中所做的那样。

然后使用 AntiForgeryDataSerializer 类反序列化令牌,更新当前用户,再次序列化并在检查之前将其放回表单中。或者完全使用您自己的属性替换 validate 方法。

或者,您可以尝试使用密码 ajax 请求发送更新后的令牌并更新表单,而不是在主表单回发上更新它。无论哪种方式,基本方法都是相同的,反序列化,更新用户,序列化,替换令牌。

string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null);
string text = context.Request.Form[antiForgeryTokenName];
AntiForgeryDataSerializer serializer = new AntiForgeryDataSerializer();

AntiForgeryData antiForgeryData = serializer.Deserialize(text); 
antiForgeryData.Username = AntiForgeryData.GetUsername(context.User);
string newToken = serializer.Serialize(antiForgeryData);    
Run Code Online (Sandbox Code Playgroud)

AntiForgeryDataSerializer 和 AntiForgeryData 是内部类,因此您必须使用一些基本的反射来调用它们的方法。