Friday, 23 March 2012
Mass Assignment - It's Not Just For Rails Anymore
If you haven’t already heard, Github (and Ruby on Rails by default) was shown to have a vulnerability where a web user could change his role and give himself commit rights to the Rails code repository via request parameters. You might be thinking that this is bad but you are safe because you are not using Ruby on Rails. But you might have the same problem. Unfortunately, the cause of the “mass assignment” problem relates to the universal web framework pattern of auto-magically binding request parameters into model objects. If you are using Fortify, we catch this in Spring MVC as Request Parameters Bound into Persisted Objects.
Model Objects
Model objects are an object-oriented representation of database entities. They provide convenience methods to load, store, update, and delete associated database entities. Hibernate and LINQ are examples of Object Relational Mapping (ORM) frameworks that help you build database-backed model objects.
Auto-binding of Request Parameters to Objects
Many web frameworks make life easier for developers by providing a mechanism for binding request parameters into request bound objects based on matching request parameter names to object attribute names (based on matching public getter and setter methods).
|
Framework |
Request Parameter Binding Method |
|
Struts 1 |
ActionForms |
|
Struts 2 |
ModelDriven Objects or Action Attributes |
|
Spring MVC < 2.5 |
Command Objects |
|
Spring MVC 2.5+ |
Controller method parameters |
|
.NET MVC |
Controller method parameters |
|
Grails and Rails |
Request parameters directly bound into model attributes |
Identifying the Problem
If you are using ORM classes as your request bound objects you probably have a mass assignment problem. Also, if you are only blacklisting (possible in .NET MVC) or whitelisting the wrong columns, this could be a problem.
Where Developers Assumptions Go Wrong
When developers create web pages to update model objects they typically provide a subset of the model attributes as <input> fields in the HTML form page.
Assume that your ORM entities include Customer and Profile:
@Entity
public class Customer {
private long id;
private String fname;
private String lname;
@OneToOne
private Profile profile;
…
//public getter and setters omitted for brevity
}
@Entity
public class Profile {
private long id;
private String username;
private String password;
private String role;
private String publicKey;
//public getter and setters omitted for brevity
}
The corresponding HTML form that updates the Customer information looks like:
<form action”/updateCustomer” method=”post” >
<input name=”customer.fname” />
<input name=”customer.lname” />
…
</form>
The developer makes an assumption that user will not know the schema of the database or attributes of the model object which are updated by the <form> above. The problem is that database schema information is leaked in the other pages of the application from input name attributes or can be guessed (password, role, etc.). So an attacker could create additional parameters to the form post such that the request would look like the following:
<form action”/updateCustomer” method=”post” >
<input name=”customer.fname” />
<input name=”customer.lname” />
…
<input name=”customer.profile.id” value=”attacker_determined_value” />
<input name=”customer.profile.role” value=”ROLE_ADMIN” />
<input name=”customer.profile.publicKey” value=”xxxx…” />
</form>
The attacker may update an existing profile (change another user’s password) or add a new record (in the profile table) with attacker controlled values or update any arbitrary field in the customer table.
Addressing the Problem
Make sure you whitelist the request parameter names used to update model objects. Or utilize one of the following secure model binding mechanisms:
|
Framework |
Secure Model Binding Mechanism |
|
Rails |
attr_accessible |
|
.NET MVC |
[Bind(Include=”columnName”)] and [Bind(Exclude=”columnName”)] attributes |
|
Grails |
Grails-safebindable plug-in |
|
Spring MVC |
DataBinder.setAllowedFields() |
|
Other Frameworks(Struts 1 & 2, etc.) |
Avoid request bound model objects |
With the other frameworks, it is probably better to not use model objects as request bindable objects. Instead, manually copy over the values until these frameworks come up to speed with implementing a solution.
Technorati Tags: "mass assignment" model objects Rails Grails Struts2 Spring MVC request binding bound







