GitHub hack: a common security flaw in webapp frameworks

Posted on Thu 08 March 2012

GitHub has faced a spectacular hack: a disappointed developer has exploited a weakness in Ruby on Rails to gain commit access to the Rails master branch and create issues in the future. As a result, GitHub asks us to confirm our ssh keys, but this can have been used to change almost any data in the system.

How's it possible?

This weakness comes from the mass assignment feature in Rails. To ease development and increase productivity, Rails allows an object to be filled with any http request parameter whose name match an attribute of the object. All is well when people use the forms provided by your web pages, because they only send parameters for attributes that you (the developer) want to change. Now things are different when someone forges a request: your object is wide open, and they can change all of its attributes.

If you have a User class with properties id, name, password, role, then a user with role "visitor" can upgrade himself to "administrator" simply using the profile edition URL. Or change the password of another user to get access to his account by changing the id value, or... etc.

Most modern web frameworks have this mass assignment feature. They allow the developer to restrict the assignable attributes by means of whitelists or blacklists, but most if not all of them have it wide open by default. This is a comfortable developer feature, but how many of them will even think of protecting their model?

A couple of examples

Rails allows whilelisting and blacklisting in the model classes. It also has scoped protection, which is useful since the assignment constraints are different e.g. in a profile edition page and a user administration page.

In the Java world, Spring MVC is also wide open by default. It allows white/black listing, but this is defined at the controller level. It is rather cumbersome to use, since you have to make sure each and every controller has a @InitBinder method that correctly configures the binder using DataBinder.setAllowedFields().

Play! Framework is also wide open by default (told you, all of them!), but has an easy scoped blacklisting with the @NoBind annotation on model attributes. Whitelisting would be more secure though.

It is to be noted that component-oriented frameworks like Wicket should not suffer from this mass assignment issue, since they have a separate page model that isolates domain objects from the request. This comes however with additional complexity and bigger server side sessions.

And finally, this mass assignment issue is not limited to page controllers but also affects less visible elements, such as JSON encoder/decoders where mass assignment is the norm. Here again, JSON libraries like Jackson, GSon, Flexjson, etc make no restriction on the attribute names by default, and so the nice REST API that you have designed may well be a giant open door for attackers.

Conclusion

This hack on GitHub has given a lot of visibility to a problem that is largely present in many of today's web framework, which have traded comfort for security by default. We may see a lot of exploits of this flaw in the coming weeks on websites using a large variety of frameworks.

So make sure your webapp is not wide open, and let's hope framework developers will consider that security by default should have priority over comfort if the price to pay is to add a couple of annotations on the model classes.



My 2011: a year like no other

Efficient storage of non-periodic time series with MongoDB