视图直接使用域模型是否危险?

Jez*_*Jez 4 asp.net-mvc entity-framework

我使用EF代码优先方法来定义我的数据库结构.目前,我将EF实体类直接传递给MVC应用程序中的一些视图.这样可以很容易地填充和保存视图,因为我可以直接拥有一个存储库,为我提供填充的EF类,如果我的控制器在回发中收到EF实体类,我可以(如果验证可以)直接通过到存储库来保存它.但是,这可能存在安全隐患吗?如果实体类中有属性我不想修改,客户端是否可以将这些属性作为回发的一部分提交并修改它们?例如,假设我有一个视图来编辑我传递此EF模型的用户:

public class User {
    [Required]
    public string Firstname { get; set; }
    [Required]
    public string Surname { get; set; }
    public DateTime DOB { get; set; }
    public bool IsDisabled { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我可能会公开Firstname,Surname并且DOB作为可编辑的表单字段,但我不希望用户能够设置IsDisabled和禁用他们的帐户.防范这种情况的最佳方法是什么?也许人们只应该直接使用视图中的域模型,当一个人认为该域模型持久化的每个属性都可以被用户设置,或者当一个人只是使​​用该域模型来显示事物时,而不是将事物保存回来数据存储?

Eri*_*sch 5

是的,将实体直接传递给您的视图可能会很危险.从技术上讲,问题是当你直接模拟绑定到实体时.

是的,你提出的情况很有可能发生.更糟.假设您使用了User对象,那么攻击者可以提交post值来执行类似设置IsAdmin true的操作,或者更改分配给用户的角色.

当然,所有这些都取决于用户是否知道(或能够猜测)数据的结构.这可能不像看起来那么困难,因为我们经常在生成的HTML中提供告示标记.

这个问题有两种解决方案:

1)使用视图模型.视图模型仅包含视图中允许的数据.您还可以控制将哪些数据复制回实体模型.

2)您可以使用该[Bind]属性为白名单和黑名单指定排除和包含各种属性.

我更喜欢使用第一种方法,因为忘记白名单或黑名单会更加困难(特别是如果你以后改变某些东西而忘记在你绑定它的任何地方更新列表).我也觉得[Bind]是作弊,鼓励邋design的设计.


Jez*_*Jez 0

我刚刚看到这篇文章:
http ://www.codethinked.com/ASPNET-MVC-Think-Before-You-Bind

它提供了几种处理此问题的方法,但我在项目中选择的方法是该方法的一种变体UpdateModel()。该方法依赖于从数据库检索可更新的对象,然后用于仅UpdateModel()设置在该对象上更新的字段。我的方法是让存储库的Update方法采用 lambda(“更新策略”),负责设置要更新的字段:

public bool UpdateUser(User updatedUser, Action<User, User> updateStrategy) {
    // Retrieve User via updatedUser.UserID...
    // Update it using updateStrategy(retrievedUser, updatedUser)...
    // Save the updated retrievedUser to DB
}

// ...
// To call the update method:
repoUser.UpdateUser(updatedUser, (existingUser, updatedUser) => {
    existingUser.Firstname = updatedUser.Firstname;
    existingUser.Surname = updatedUser.Surname;
    existingUser.DOB = updatedUser.DOB;
});
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,它都会防止更新您不想更新的任何字段,无论它们是否已发布到操作方法。当然,恶意的客户端可以修改隐藏UserID字段,但我认为不需要警惕;它只是更改正在更新的用户,如果您的系统允许他们更新他们不应该有权限的用户,那么这本身似乎就是一个安全缺陷。