ASP.NET MVC 安全问题之over-posting
模型绑定是ASP.NET MVC提供的强大功能,可遵照命名约定将输入元素映射到模型属性,从而极大地简化了处理用户输入的过程,然而,这也成为了用户通过猜测等手段得知了后端数据Model的属性名称,在数据更新或添加的时候提交了本不应该允许用户更改的数据库字段,并且在服务器端因为没有进行防御而将恶意提交的数据写入了数据库。
过度发布现象
ASP.NET MVC 通过使用一些命名约定来映射模型属性GET
和POST
操作。但是,这种便利带来了一个安全漏洞:攻击者可以填充模型的属性,即使这些属性未在表单中显示。
考虑PlaceReview
绑定到动作的模型。
public class PlaceReview
{
public int ReviewID { get; set; } // PK
public int PlaceID { get; set; } // FK
public Place Place { get; set; } // FK
public int NumberOfLikes { get; set; }
public string UserName { get; set; }
public string UserComment { get; set; }
}
现在考虑该操作仅对模型的UserName
和UserComment
属性感兴趣。
<ul>
<li>
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
</li>
<li>
@Html.LabelFor(m => m.UserComment)
@Html.TextBoxFor(m => m.UserComment)
</li>
</ul>
恶意用户可以操纵查询字符串或发布数据以添加信息并更改模型的其他属性。例如,他可以添加“ NumberOfLikes = 5000
?并且相应的属性将相应地填充到服务器端应用程序中。
使用 [Bing] 特性防御重复提交攻击
1、可以使用Bing白名单来指定模型绑定的字段,比如 [Bing(Include="Name,Comment")]
也可以使用黑名单来排除禁止绑定的字段,比如 [Bind(Exclude="ID,DateTime")]
一般情况下,白名单比黑名单更安全一些。
[System.Web.Mvc.Bind(Include="UserName, UserComment")]
public class PlaceReview
{
public int ReviewID { get; set; } // PK
public int PlaceID { get; set; } // FK
public Place Place { get; set; } // FK
public int NumberOfLikes { get; set; }
public string UserName { get; set; }
public string UserComment { get; set; }
}
2、另一种方法是使用UpdateModel或者TryUpdateModel方法来接收一个绑定列表,例如:
UpdateModel(placeReview, "PlaceReview",new string[] { "UserName", "UserComment" });
3、避免直接绑定到数据模型也是有效防御重复提交攻击的一种方式。通过一个视图模型,只缓存允许用户设置的属性来阻止攻击。
public class PlaceReviewModel
{
public string UserName { get; set; }
public string UserComment { get; set; }
}