GitHub was recently compromised by a vulnerability in Ruby on Rails know as mass assignment. This vulnerability is thought to not only affect a large number of Ruby-based websites, but also those using ASP.NET MVC and other ORM-backed web frameworks.
Mass assignment by itself is a safe and effective technique for mapping form data to objects. The equivalent in ASP.NET MVC, known as data binding, is likewise safe when used on its own. The actual vulnerability comes from the reckless mixing of mass assignment with an ORM.
Consider this scenario: a database contains a “user” table with a mixture of sensitive and non-sensitive data. Perhaps it has some columns for a user’s display name, email address, and whether or not they are an administrator. A developer wishes to build a screen that allows for editing the display name and email address. To do so they use Rails or MVC scaffolding to automatically generate the domain objects and possibly the view itself. Then they remove from the view any non-user editable fields like the “Is Administrator” checkbox.
A security hole is created if the developer forgets to also remove the IsAdministator property from the domain object. If they don’t do so, the mass assignment/data binder can be tricked into updating that property along with legitimate changes. When the record is then saved, the ORM libraries silently store the new values.
There are three tenable solutions to this problem:
- Flag the non-updatable properties so that the mass assignment/data binder will ignore them.
- Completely remove any properties on the business object that are not actually needed.
- Create models specifically for receiving update requests and manually map them to the ORM object or stored procedure call.
It should be noted that this isn’t a new vulnerability. It is easy to find warnings about mass assignment from four or five more years ago with titles such as “Hackers Love Mass Assignment” and “Use attr_protected or we will hack you”. The only difference this time around is the high-profile nature of the victim.6 Discuss
It is. The more interesting question is why it takes rails 7 years (and counting) to come to this conclusion.
I'll take it one further and sing my song about the Rails ActiveRecord implementation here, which is tangentially related.
The promise of AR is to reflect on the database at startup and then "magically work".
The problem in rails is that nothing magically works. What you get out of the box is an insecure world-writable model, as illustrated by this bug. Then you begin scattering your truth over incremental (hand-crafted!) migrations, the model, and the controller, until nobody other than a cascade of unit-tests can even make sense of the interdependencies anymore.
In a world where there is not even a central place to look up which fields exist on a model and what their constraints are - short of runtime introspection, where database constraints live happily alongside and independently of model constraints, where opaque bits of ruby-logic buried in various gems add their own magic to the mix, in such a world it's really no surprise they chose to default to "all fields writable".
Because if they forced the user to do the sensible thing and explicitly list the allowable fields then where's the advantage over a declarative approach (like e.g. Django) anymore?
Imho it's long overdue to take a step back and revisit whether AR is still worth having, or ever was. Imho it causes way more problems than it solves, in contrast to the declarative approach.