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)
当前用户存储在表单数据的防伪令牌中,并在回发时与当前用户进行比较。
您应该能够在回发时提取表单令牌,就像 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 是内部类,因此您必须使用一些基本的反射来调用它们的方法。
| 归档时间: |
|
| 查看次数: |
4007 次 |
| 最近记录: |