ASP.NET MVC 3中默认的强类型编辑页面通常会公开实体的所有字段。虽然这通常是可行的,但某些领域存在安全风险。例如,简化的杂志订阅实体可能如下所示:
public void Subscription() {
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public DateTime SubscribedThru { get; set; }
}
例如,如果我提供编辑页面以允许用户更改自己的地址,那么包含SubscribedThru
字段会带来安全风险,因为知识渊博的恶意用户可以通过伪造为自己提供10年的免费订阅日期(即使我使用@Html.HiddenFor(model => model.SubscribedThru)
。所以我不会在编辑页面html(通过剃刀)中以任何方式包含该字段。
我认为答案可能是阻止对控制器中Edit方法的SubscribedThru
进行绑定尝试,例如:
[HttpPost]
public ActionResult Edit([Bind(Exclude="SubscribedThru")] Subscription subscription) {
if (ModelState.IsValid) {
db.Entry(subscription).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(subscription);
}
当我到达SaveChanges();
行时,它会抛出错误The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
我认为SubscribedThru日期(正确?)不存在,并且空值小于SQL Server可以处理的值。让我感到惊讶的是,当我将Binding排除在外时,它甚至会尝试更新该字段。
到目前为止,我最好的解决方案似乎是创建一个省略SubscribedThru日期的自定义ViewModel,但这似乎是很多重复的字段,验证等;如果可能的话,我想让一个字段SubscribedThru
免于用户编辑。
我不能说我完全理解UpdateModel
和TryUpdateModel
方法,并想知道这是否是一个方向?我和他们一起玩,EF因为有重复的对象(相同的密钥)而引发错误。
此外,我不清楚订阅数据是否从控制器中public ActionResult Edit(int id)
的初始加载一直保留到最终[HttpPost]
public ActionResult Edit(Subscription subscription)...
方法,或者行{{1}尝试并设置所有数据(我认为它只是设置一个标志,表示“编辑 - 所以 - EF-should-save-this”)。
我是一名长期的.NET开发人员,刚刚进入我的第一个ASP.NET MVC项目,所以我可能会忽略一些非常明显的东西。谢谢你的帮助!
答案 0 :(得分:3)
到目前为止,我最好的解决方案似乎是创建一个省略SubscribedThru日期的自定义ViewModel,但这似乎有很多重复的字段,验证等;
这正是你应该做的事情,以保持整洁和安全整洁。 AutoMapper可以缓解ViewModel
变异性头痛。
答案 1 :(得分:1)
此页面包含使用TryUpdateModel
更新模型的示例(清单4):
http://www.asp.net/mvc/tutorials/older-versions/models-(data)/creating-model-classes-with-the-entity-framework-cs
您只能将允许编辑的字段列入白名单,这样可以消除安全风险。