4

我使用 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; }
}

我可能会将FirstnameSurname和公开DOB为可编辑的表单字段,但我不希望用户能够设置IsDisabled和禁用他们的帐户。预防这种情况的最佳方法是什么?或许只有在认为用户可以设置由该域模型保存的每个属性都可以的情况下,或者仅在使用该域模型来显示事物而不是将事物保存回数据存储?

4

4 回答 4

5

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

是的,你提出的情况很有可能发生。更糟。假设您传递了一个 User 对象,那么攻击者可以提交一个 post 值来执行诸如将 IsAdmin 设置为 true 之类的操作,或者更改分配给用户的角色。

当然,这一切都取决于用户是否知道(或能够猜测)您的数据结构。这可能并不像看起来那么困难,因为我们在生成的 HTML 中经常有提供提示的迹象。

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

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

2)您可以使用该[Bind]属性来指定排除和包含以将各种属性列入白名单和黑名单。

我更喜欢使用第一种方法,因为忘记将某些内容列入白名单或列入黑名单要困难得多(特别是如果您稍后更改某些内容并忘记在绑定它的任何地方更新列表)。我也觉得[Bind]是作弊,鼓励草率的设计。

于 2012-10-14T23:57:42.887 回答
3

你真的不应该使用你的实体模型作为视图模型,我认为你在这里的例子确实比我在其他任何地方看到的更好地突出了这一点。

如果您的控制器在发布时接受了,User那么是的,您将公开要发布的数据。如果您直接映射发布的用户而不检查无效提交,那么您会将问题持久化到数据库中。

于 2012-10-15T00:02:00.530 回答
2

最好的选择是使用视图模型。这样,您既可以防止有人试图访问不可见的属性,例如您的IsDisabled,因为它根本不在视图模型中,也可以将您的域与表示层分离。如果您曾经需要扩展您的 EF 实体(更多属性、更多关系等等),您的视图模型可能不需要更改。

于 2012-10-14T23:56:56.327 回答
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;
});

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

于 2013-03-20T10:23:49.213 回答