A little over a year ago (wow, it seems like only yesterday), I made a post called Think Before You Bind. In this post, I presented to you exactly why you want to make sure that when you are doing automatic binding to models in ASP.NET MVC, you need to absolutely make sure that you are only binding to the properties that you expect. The reason for this, is that in ASP.NET MVC you really have no way of telling what was supposed to be posted to the server, and what wasn’t, so someone could tamper with, or create fake, post data and overwrite properties that you weren’t expecting to be changed.
This isn’t something unexpected, but it is definitely not something that Web Forms developers have to really consider when building their solutions. On the flip side though, ASP.NET tracks what fields are supposed to be on the form which ties you into a fairly static number of fields, unless you want to hack your way around that model. And I think many of us know how ugly that can get…
So, the basic problem is that ASP.NET MVC doesn’t care what you render to the user, and it doesn’t care what gets posted back. If the post value name and the property name match, then ASP.NET MVC is going to map the value onto the property, even if you never rendered a field by that name. It is a concern, but one that is easily avoided by using a very simple approach. And that approach is to use models that are specific to your views, usually to referred to as View Models (not to be confused with the MVVM – Model-View-ViewModel pattern). View models are useful for a number of reasons, but in this case we are leveraging them so that you can expose a surface with only the properties that you want bound, like this:
And that approach works well, but really only if your objects are ever being used in one context. What happens if you need to edit an object as both an end-user and an administrator, certainly you don’t want to allow users to edit the same properties as an admin. Well, if you used the same view model, then you would be setting yourself up for a potential security hole, since the end user could (as we explained earlier) add some bad data into the post, and update the view model in ways that you didn’t expect. So, how do you fix this?
Well, one solution is to create two different view models, one for the end user, one for the admin. But that begs the question, what if we need to have even more contexts? Or what if we had interfaces which edited pieces of a larger object? Do we just keep introducing more and more view models? You could, but that would be a lot of work…. if only we had some way to create a view on top of an object which would expose only the properties that we wanted to see. Hmmmmm… That sure would be a neat language feature, you know, something like this:
For the astute, you’ll notice that I just explained interfaces, and last time I checked, C# has those. Thanks to a comment from my good friend Simone Chiaretta (and others), the idea of using a single view model with different interfaces was proposed. Then instead of using the class type to bind, you could just use the interface! Something like this is the result:
public class PersonViewModel: IEditPersonAsUser { public string FirstName { get; set; } public string LastName { get; set; } public string Role { get; set; } public string EmailAddress { get; set; } } public interface IEditPersonAsUser { string FirstName { get; set; } string LastName { get; set; } string EmailAddress { get; set; } } internal interface IEditPersonAsAdmin { string FirstName { get; set; } string LastName { get; set; } string EmailAddress { get; set; } string Role { get; set; } }
The downside to this is that you can no longer use the automatic model binding that ASP.NET MVC gives you. The reason for this is fairly self explanatory, how would ASP.NET MVC know which model to bind for this method?
public ActionResult Edit(IEditPersonAsUser personModel)
The answer is, "it wouldn’t". You could theoretically put that interface on any number of implementations, and so there is no quick and reliable way to pick out the right implementer. (Well, when I say "no way", you could look for a single implementer, and if you find more than one, you just throw an exception) This is easy enough to work around though. You can write code to perform the automatic binding manually (this is just screaming for a custom model binder!):
var personViewModel = new PersonViewModel(); UpdateModel<IEditPersonAsUser>(personViewModel);
Notice here that we are telling the UpdateModel method to bind the view model using the IEditPersonAsUser interface. This works well, but it would still be better if we could avoid those few lines of code over and over. We could put a small method like this in a base controller, and make it even easier:
private T Bind<T, U>() where T : U, new() where U : class { T model = new T(); UpdateModel<U>(model); return model; }
Now you could just bind the model like this:
var personViewModel = Bind<PersonViewModel, IEditPersonAsUser>();
A tiny bit easier and cleaner. Now you can create view models for specific entities, and then you can reuse them in multiple scenarios without having to worry a bunch about white lists, black lists, or creating a ton of different view model classes.
As I mentioned earlier though, this is just crying out for a custom model binder, we could set one up so that when it sees an interface type it simply searches for the one type which implements that interface and then throws an exception if it finds more than one. Since our whole purpose here is to use an interface to constrain a single view model to different views of the same model, that shouldn’t hurt us at all. Maybe I’ll implement that for you in a future post.
I hope that you found this post informative and useful, if you have any ideas for things that could be improved or modified, please post me a comment!
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
Cool, hadn’t thought of the multiple interfaces approach before. I like that.
I tend to be a little leery of biding in post methods, ever since watching the "hackers love mass assignment" episode of railscasts. Basically, watch out for hackers xss to change form fields that could cause problems with your model. However, that wasn’t accounting for using a View Model, which might lower the threat.
Nice post.
I hope something like this makes it into the next release of ASP.NET MVC. The model binding definitely seems like the biggest security hole that is very easy to unintentionally create. I’m going to try your method. The other approach with view-specific models seems to be using AutoMapper (or similar). Do you have any thoughts on that approach?
Argh — I didn’t read closely enough. Consider my question answered!