Why you shouldn't use Html.beginForm + UpdateModel on ASP.NET MVC

Published:
I've found this issue almost accidentally, however it seems so clear and logical to me that I'm surprised that there's no specific information on the matter (at least at first glance).

Is not unusual to see people using the beginForm helper on ASP.NET MVC applications, this is true to the point that the creation of a Create/Edit View on VS includes it on your code by default.

This helper just builds a <form> tag saving you some repetitive typing, it gets your current http petition and builds an action and a method for the form. To this point maybe there's nothing that triggers your alarms, however there is. The default method uses your current url, wich can be manipulated directly on the browser by the user, to build the action of the form; this way a malicious user can inject extra parameters on your server call.

Ok, what's the problem? My model classes and controller will deal only with those parameters I define, so...

Well, actually is highly possible that you're using one of the most popular utilities of MVC framework on your form controllers: UpdateModel. This method map the fields on your form action directly into your business model whenever it's possible. It's a huge advantage when dealing with complex and big data structures, as it saves a lot of repetitive coding, however, if your business model has a field that's not published through the form but comes on the HttPost, UpdateModel will recognize it and update the data.

Let's try to put it all together on an actual example:

Suppose you have an application where users can edit some of the data in their profile but cannot update some specific data unless they are have a higher role. Say, for example, that they cannot update their email address.

When you build the editing profile form, you build the restricted fields only if the user on session has the higher role.

Unfortunately, if your form is built with Html.beginForm(), a savvy user can alter the url of the form from something like http://yourApp/Profiles/Edit/<ProfileId> to http://yourApp/Profiles/Edit/<ProfileId>?email=myHomeEmail@mail.com

On loading the altered url, if you look at the source code, you'll see that the generated form is:

<form action="/Profiles/Edit/<ProfileId>?email=myHomeEmail@mail.com" method="post" />

Of course, when your form submits the email parameter will be caught by UpdateModel and included into your business model data update.

This example could seem fairly benign, however the exploit possibilities are far larger.

As an immediate fix I recommend to build <form> tags manually. They are critical enough that they should not be coded automatically. However maybe there are intermediate solutions to this. I have to do some research with beforeUpdate overloads and see if there are any that allows you a strict control of the action parameter.

I hope this brief article helps you to make your applications a bit more secure.
1
4,632 Views

Comments (4)

Author

Commented:
Since I wrote this article I've found more info on the matter and I've seen there is more danger than I initially thought. I'll try to find time to write a more exhaustive and clearer one on the dangers of blind model binding
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
...a savvy user can alter the url of the form from something like...
I'm confused:  Are you saying that a savvy user could modify the URL on the client, or on the server? If the former, then how exactly does manually writing your own <form> tag mitigate this?

...however the exploit possibilities are far larger.
Such as?

Author

Commented:
It's been some time since I wrote this, and almost had forgot about it. However, there's a real problem in the use of blind model binding, as anyone can use a tool to send petitions to server or just code manual petitions that attacks your model action sending different parameters.

If you had used UpdateModel without defining the parameters of your model that are public to editing, those malicious petitions could on the end pass the model binding and save to your database.

I'm not exactly sure what I mean two years ago about using manual forms instead of beginForm, however you must use the list of open parameters to UpdateModel to avoid any private data from being updated.
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
Don't sweat it. I just stumbled across the article. I have been using MVC/Web API over the past couple of years, and I wanted to make sure I understood what you were presenting.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.