16

为什么开发人员会Bind在 ASP.NET MVC 项目中的 ViewModel 对象上使用该属性,这会对应用程序产生不利影响?

[Bind(Include = "Id,Name")]
[MetadataType(typeof (MyViewModelValidation))]
public class MyViewModel
{
    public string CustomerProductUserName { get; set; }

    [Display(Name = "Name")]
    public string Name { get; set; }

}

public class MyViewModelValidation
{
    [HiddenInput(DisplayValue = false)]
    public int Id { get; set; }

    [Required]
    public string Name{ get; set; }
}
4

4 回答 4

20

首先,您不需要MetadataType为 ViewModel 创建类。您可以直接在 ViewModel 中使用数据注释属性。MetadataType类用于由 EF 或其他 ORM 自动生成的模型,因此您可以使用数据注释属性而无需接触自动生成的代码。

Bind也不必使用该属性 - 除非您想使用Bind 属性的属性,以分别在绑定中或从绑定中包含或排除模型中的属性IncludeExclude

例如,在您问题的代码中,从您的视图提交模型时,只有Id和属性将被绑定。Name即使您在 View 中有输入CustomerProductUserName,当您提交表单时,该属性也将始终为空。这在您不希望将自动生成的 ID 字段包含在绑定中的情况下很有用。

从绑定中排除的属性也从验证中排除,因为验证是作为模型绑定的一部分完成的。Bind此外,出于安全原因,您可以使用该属性;例如,当您想确保只将模型中的属性发布到控制器时。

于 2013-08-16T15:32:14.347 回答
15

使用绑定属性的目的是防止攻击者在发布请求时分配属性值或控制要绑定的属性。

让我们假设,您有一个名为的类Member和一个保存成员的创建方法。但是您不希望用户发送MemberType属性值。

Class Member  
{  
    public int MemberId { get; set; }  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
    public string MemberType { get; set; }  
}  

[HttpPost]  
Public ActionResult Create(Member member)  
{  
    Save(member);  
}

假设现在,您只提供作为默认值的常规成员类型。您可能认为您可以通过不允许输​​入MemberTypeProperty 来阻止用户发送 MemberType 属性的值。但是当用户发布成员对象时,攻击者可能会拦截请求并在请求中发送 MemberType 值, MemberId=1&FirstName=Chandra&LastName=Malla&MemberType=Premium并将成员保存为高级成员。为了防止这种情况,您可以使用属性 装饰Member类。Bind

[Bind(Include="MemberId,FirstName,LastName")]  
Class Member  
{
    ...

或者

[Bind(Exclude="MemberType")]  
Class Member  
{  
    ...

现在如果Member发布对象,则不会发布 MemberType 属性值。

如果您使用的是 ViewModel,则可能不必使用绑定属性,因为您可以在 ViewModel 中省略 MemberType 属性。

Class Member  
{  
    public int MemberId { get; set; }  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
    public string MemberType { get; set; } 
}  

Class MemberViewModel  
{       
    public int MemberId { get; set; }   
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
}  

[HttpPost]  
Public ActionResult Create(MemberViewModel memberviewmodel)  
{  
    Save(memberviewmodel);  
}

如果你没有很好地设计你的模型和/或 ViewModel 并且不使用绑定属性来避免发布你不想要的属性,那可能会产生不利影响。

于 2014-11-12T04:40:32.363 回答
5

此外,如果您想在从模型重命名属性时防止重构问题,您可以执行以下操作:

public async Task<ActionResult> Create([Bind(Include = nameof(Foo.Bar1)+","+nameof(Foo.Bar2)+","+nameof(Foo.Bar3))] Foo fooObj)

如果您现在重命名“Bar1”,您的包含绑定仍然有效。

于 2018-08-21T12:07:13.443 回答
4

您可以使用 Bind 属性来控制模型绑定器如何将请求转换为对象。使用 Bind 属性的最常见方式是从绑定中排除Id 属性。例如,Persons 数据库表包含一个名为 Id 的列,它是一个 Identity 列。因为 Identity 列的值是由数据库自动生成的,所以您不希望将表单字段绑定到此属性。

另一方面,假设模型的属性特别敏感,恶意用户可以在提交表单时简单地将其附加到 URL 中。如果这样做了,模型绑定器将在绑定过程中愉快地发现和使用数据值。通过 Bind 属性,您可以保护您的应用程序免受此类攻击。

例如,当您要更新实体并且 ID 对您很重要时,使用 Bind 属性可能会产生问题。

于 2013-08-16T16:02:23.177 回答