ASP.NET - Overposting/Mass Assignment Model Binding Security

Datetime:2017-04-19 05:21:52         Topic: ASP.NET          Share        Original >>
Here to See The Original Article!!!

This little post is just a reminder that while Model Binding in ASP.NET is very cool, you should be aware of the properties (and semantics of those properties) that your object has, and whether or not your HTML form includes all your properties, or omits some.

OK, that's a complex - and perhaps poorly written - sentence. Let me back up.

Let's say you have this horrible class. Relax, yes, it's horrible. It's an example. It'll make sense in a moment.

public class Person
{
    public int ID { get; set; }
    public string First { get; set; }
    public string Last { get; set; }
    public bool IsAdmin { get; set; }
}

Then you've got an HTML Form in your view that lets folks create a Person. That form has text boxes/fields for First, and Last. ID is handled by the database on creation, and IsAdmin is a property that the user doesn't need to know about. Whatever. It's secret and internal. It could be Comment.IsApproved or Product.Discount. You get the idea.

Then you have a PeopleController that takes in a Person via a POST:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Person person)
{
    if (ModelState.IsValid)
    {
        _context.Add(person);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(person);
}

If a theoretical EvilUser found out that Person had an "IsAdmin" property, they could "overpost" and add a field to the HTTP POST and set IsAdmin=true. There's nothing in the code here to prevent that. ModelBinding makes your code simpler by handling the "left side -> right side" boring code of the past. That was all that code where you did myObject.Prop = Request.Form["something"]. You had lines and lines of code digging around in the QueryString or Form POST.

Model Binding gets rid of that and looks at the properties of the object and lines them up with HTTP Form POST name/value pairs of the same names.

NOTE:Just a friendly reminder that none of this "magic" is magic or is secret. You can even write your own custom model binders if you like.

The point here is that folks need to be aware of the layers of abstraction when you use them. Yes, it's convenient, but it's hiding something from you, so you should know the side effects.

How do we fix the problem? Well, a few ways. You can mark the property as [ReadOnly]. More commonly, you can use a BindAttribute on the method parameters and just include (whitelist) the properties you want to allow for binding:

public async Task<IActionResult> Create([Bind("First,Last")] Person person)

Or, the correct answer. Don't let models that look like this get anywhere near the user . This is the case for ViewModels . Make a model that looks like the View. Then do the work. You can make the work easier with something like AutoMapper .

Some folks find ViewModels to be too cumbersome for basic stuff. That's valid. There are those that are "All ViewModels All The Time," but I'm more practical. Use what works, use what's appropriate, but know what's happening underneath so you don't get some scriptkiddie overposting to your app and a bit getting flipped in your Model as a side effect.

Use ViewModels when possible or reasonable, and when not, always whitelist your binding if the model doesn't line up one to one (1:1) with your HTML Form.

What are your thoughts?

Sponsor:Check out JetBrains Rider : a new cross-platform .NET IDE. Edit, refactor, test, build and debug ASP.NET, .NET Framework, .NET Core, or Unity applications. Learn more and get access to early builds !








New