Security Vulnerability of passing Domain objects to Controller Actions in MVC

Sometimes I come across ASP.NET MVC or WebAPI code that contains a security flaw where developers will accept the same model in their controller action’s parameter that they are passing to their data access. This model can be a Domain Object used in an ORM such as Entity Framework or NHibernate.

A client can send additional properties in the json body, form collection or whatever content type you are accepting, that will populate unintended properties in the domain object if available, including navigational properties and foreign keys. Usually this domain is then used directly in the ORM either in an update or create.

Take for example, the scenario of updating a user. This user has a Verified property that can only be set by admins and a list of UserRoles that determine the authorization of that user. That is represented in the domain code below:

public class Role
{
  public int Id {get; set;}
  public string Name {get; set;}
  public virtual ICollection<User> Users {get; set;}
}

public class User
{
  public int Id {get; set;}
  public string Name {get; set;}
  public bool Verified {get; set;}
  public virtual ICollection<Role> Roles {get; set;}

}

Now lets implement an action that allows the user to update their name. In our UI we only provide a field to update only the Name, or document our API to say we’re accepting only Name.

[HttpPut]
public async Task<IHttpActionResult> Put(User user)
{
  db.Users.Attach(user);
  var entry = db.Entry(user);
  db.Entry(entry).State = EntityState.Modified;
  db.SaveChanges();
}

We are expected that all request with a json body or equivalent form data to look like this:

{
  Id: 1,
  Name: "Zezima"
}

Now consider a request that looks like this:

{
  Id: 1,
  Name: "Zezima",
  Verified: true,
  Roles: [{
    Id: 1,
    Name: "Admin",
  }]
}

A request like this allows the user to set his own account to be verified and with a bit of luck, add the role of admin.

Business data and schema can be guessed by the nature of the application, Verified could be guessed easily and maybe alittle more guessing for Roles. If your Get actions actually returns domain objects, you would have given all this schema information for free.

Solution

  1. Create Models or View Models specifically for each action that contains only exactly what your view needs or what your action requires.
  2. Tell your ORM exactly what fields to update.