You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC中如何保护继承基类的复杂对象免受批量赋值攻击

解决批量赋值问题的方案及属性保护建议

一、替代[Bind(Include)]的最佳方案:使用视图模型(ViewModel)

直接用[Bind(Include)]罗列大量属性确实会让代码臃肿且不易维护,最稳妥的方式是创建视图模型(ViewModel)——它只包含前端需要提交的属性,从根源上避免不必要的属性暴露,彻底解决批量赋值风险。

示例代码:

// 视图模型:仅保留创建员工时需要用户提交的字段
public class CreateEmployeeViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Position { get; set; }
    public string Department { get; set; }
    public string Gender { get; set; }
    public string Address { get; set; }
    public int Hours { get; set; }
    public bool IsPartTime { get; set; }
    
    // 若允许用户提交福利选项,就包含对应的属性
    public bool Health { get; set; }
    public bool Vision { get; set; }
    public bool Dental { get; set; }
    public bool Life { get; set; }
}

// 修改后的AddEmployee方法
[HttpPost]
public ActionResult AddEmployee(CreateEmployeeViewModel vm)
{
    if (ModelState.IsValid)
    {
        // 手动将视图模型映射到Employee实体
        var employee = new Employee
        {
            FirstName = vm.FirstName,
            LastName = vm.LastName,
            Position = vm.Position,
            Department = vm.Department,
            Gender = vm.Gender,
            Address = vm.Address,
            Hours = vm.Hours,
            IsPartTime = vm.IsPartTime,
            Health = vm.Health,
            Vision = vm.Vision,
            Dental = vm.Dental,
            Life = vm.Life
            // Salary、Id这类敏感/自动生成的属性,完全不在此处赋值
        };
        
        // 执行保存等后续逻辑
    }
    return View("Home");
}

说明:视图模型精准控制了前端能提交的字段,像Salary(薪资)、Id(主键,通常由数据库自动生成)这类不需要用户输入的内容,根本不会出现在ViewModel中,自然无法被恶意赋值。

二、其他可选方案

1. 手动绑定请求参数

如果场景简单,也可以直接从Request中逐个提取允许的参数,再赋值给Employee:

[HttpPost]
public ActionResult AddEmployee()
{
    var employee = new Employee
    {
        FirstName = Request.Form["FirstName"],
        LastName = Request.Form["LastName"],
        Position = Request.Form["Position"],
        // 只绑定你允许的属性,跳过Salary、Id等敏感字段
    };
    
    // 验证及保存逻辑
    return View("Home");
}

缺点是代码量略大,但适合小型项目或临时场景。

2. 使用DTO(数据传输对象)

和ViewModel思路一致,DTO更偏向服务层之间的数据传输,在前后端分离场景中同样能起到防批量赋值的作用,本质都是通过“窄化数据范围”来规避风险。

三、是否需要保护Employee和Benefits的属性?

是的,必须保护,可从两方面入手:

  • 限制属性的可访问性:对于不需要外部直接修改的属性(如Id、Salary),将其setter设为private或protected,只允许通过构造函数或特定方法赋值:
public class Employee : Benefits
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // Salary设为私有setter,仅能通过内部方法修改
    public string Salary { get; private set; }
    public string Position { get; set; }
    public string Department { get; set; }
    public string Gender { get; set; }
    public string Address { get; set; }
    public int Hours { get; set; }
    // Id通常由数据库生成,设为私有setter
    public int Id { get; private set; }
    public bool IsPartTime { get; set; }   

    // 提供修改薪资的方法,可添加验证逻辑
    public void UpdateSalary(string newSalary)
    {
        if (!string.IsNullOrWhiteSpace(newSalary) && /* 额外验证逻辑 */)
        {
            Salary = newSalary;
        }
    }
}
  • 禁止直接将实体作为Action参数:直接接收Employee实体的话,攻击者可以手动构造表单字段(比如Salary、Id)提交,即使前端没显示这些字段也能赋值。用ViewModel/DTO隔离实体和请求,才是更安全的做法。

内容的提问来源于stack exchange,提问作者Bill Kindig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 13:07:47