The Theo Spears Blog

Blogging Considered Harmful (Considered Harmful)?

Object binding with html

First posted 2006-06-28 00:00:00.000002+00:00

Abstract

It is very useful to be able to automatically process information provided by the user in forms, based purely on the layout of the form. However any such automated request processing is potentially vulnerable to malicious users manipulating the request. Here we outline some of these problems and a way of overcoming them.

The Goal

The maintainability of applications is greatly enhanced by cohesiveness, keeping closely related functionality together, and separating it from less strongly related functions. One example of this is separating the code representing business objects from the code which displays these objects. A popular way of achieving this separation is the Model-View-Controller (MVC) framework.

With MVC it is common to map specific fields in the view (with html this might be particular <span> or <input /> tags to particular members of the objects comprising the model. A very common scenario is mapping particular object members to particular <input /> tags in the form, and then updating the members of the object with the new values the user has entered.

Whilst it is possible to write code to do this manually in each instance it is far more convenient to indicate which fields map to which which object members and have some generic code which can do this mapping for any form and any object. Here I discuss various obstacles encountered in doing this and how they may be overcome.

A naive solution

(All examples here are in PHP, as this is the language I am currently working in, however the ideas expressed should translate to other web environments.)

Assuming we do not want to make all fields of the object available to be editted the view will specify which fields should be available to edit, and will also need to specify where in the resulting page these fields are. In order to facilitate binding the contents of the fields to existing values from the object helper functions can be used to create the actual fields.

<form method="POST">
<?php objectId('Pizza'); ?>
Topping: <?php displayInputField('Pizza.Topping'); ?> <br />
Size: <?php displayInputField('Pizza.Size'); ?> <br />
Olives: <?php displayInputField('Pizza.Olives'); ?> <br />
<?php displaySubmitButtion(); ?>
</form>

displayInputField() is a helper function which looks at the value of the Pizza object and displays an appropriate input element depending on its type, filling the default value with the current value from the object. The input element is given a name according to some naming scheme such that it can easily be identified afterward. The resulting html might look like this.

<?php displayForm(); ?>
<input type="hidden" name="data__pizza__id" value="52" >
Topping: <input type="text" name="data__pizza__topping" value="Mozzarella"> <br />
Size: <input type="text" name="data__pizza__size" value="Large"> <br />
Olives: <input type="checkbox" name="data__pizza__olives" value="Yes"> <br />
<input type="submit" value="Update">
</form>

On submission the contents of the data array is examined. Each object submitted is identified (in this case 'pizza') and the relevant object is fetched from the database using the 'id' field. Then the values are updated using the fields starting with 'datapizza' and the object is stored in the database again, with no manual code intervention.

Problems

This naive solution has a number of problems, mainly associated with how little protection it has against malicious users.

  1. By specifying additional entries in the result sent back, an attacker can edit object members which are not meant to be user-editable, e.g. setting the 'admin' flag for their profile.

  2. By changing the 'id' parameter the user can change the values for other objects, potentially changing someone else's pizza order

  3. By carefully constructing the right query, the user can in fact edit any value for any object in the system.

The Solution

We clearly need to put in place additional measures to

As much as possible, we would like to do these without introducing additional complexity into the view code.

Solving field spoofing

One way to solve field spoofing would be at the object level, specifying which fields are read-write and which are read-only. This is not an acceptable solution as there are some fields which should e.g. be only editable by some users. It is also non-ideal as it requires us to add more information to the system. We have already specified which fields should be editable through this form, so following the principle of Don't Repeat Yourself, we shouldn't do so again.

The problem is information about what fields where included is available when the form is being constructed (we can easily record it from the displayInputField calls) but it is not available when the form is being processed. We need to store this information when the form is generated and then recall it when processing the form.

Obviously different forms will have different fields available so we need to have some way to identify the form. One solution is to generate a unique form identifier each time displayForm is called and associate this with the list of fields on the server. However for a busy site this will result in a lot of duplicate information being stored, and there is also the question of how long this information should be kept for - a user will not want to leave their computer with a page open, come back a few hours later and find they have lost their work because a form session has expired.

A second, better, solution is to store this information as part of the form, in a hidden input field (the "signature string"). This information is non-sensitive (the user can already see the list of fields supplied) however it must be secure against tampering. To do this we can include a hash of the information with a secret on the server. e.g. for the example above we might use a signature string of "pizza_id:pizza__topping:pizza_size:pizza_olives|4A3F98E0F" where "4A3F98E0F" is the result of hashing "my_server_secret|pizza_id:pizza__topping:pizza_size:pizza_olives". By checking the hash the server can be sure the client has not tampered with the supplied values.

(Note for the paranoid: As both the hash and part of the cleartext are sent to the client it is feasible for the client to launch a brute force attack to try to determine the server secret. This could be avoided by having a list of server secrets, generating a new secret for example every hour, and having each secret only valid for up to 8 hours. This way the time available for a brute force attack is greatly reduced, whilst still allowing a reasonable length of time for the user to complete the form. Needless to say, a long and unguessable server secret should be used.)

Solving object spoofing

To an extend we have already solved object spoofing, in that a user cannot edit an object of a different type to the one they are meant to be editting. However, it is still possible for the user to change the id field and edit a different object. This problem is best tackled by solving a more general one - preventing users from manipulating any hidden fields. We simply need to include the values of all hidden fields in the hash we generate. We could for example hash the string "my_server_secret|pizza_id:pizza__topping:pizza_size:pizza_olives|pizza_id=52" instead. As only hidden field values are included in the hash we need to indicate in our signature string, for example we could use "pizza_id|pizza__topping:pizza_size:pizza_olives|4D4C32AF71".