The symfony framework has always provided the tools needed by the developers to secure their applications.

We were one of the very first framework to provide a dedicated sub-framework to automatically escape the template variables and protect your application against XSS (this strategy has also been adopted by Django recently).

With the new form framework, we have added an automatic protection against CSRF. Speaking of the form framework, we have also added a lot of security features to protect you against all sort of injections.

Last week, I have read an interesting post about mass assignment vulnerability in Rails. The "Mass assignment pattern" is a way to easily update an object based on the values submitted from a browser. Here is a simple example, based on Propel:

$user = UserPeer::retrieveByUsename('fabien');
$valuesFromForm = $request->getParameter('user');
 
$user->fromArray($valuesFromForm);
 

Can you spot the vulnerability? The problem lies in the last line of this short snippet of code. The fromArray() method updates the object properties based on the values passed as an argument. But what if someone injects an extra is_admin parameter in the form to gain administrator rights? Propel will happily update this column in the database, even if there was no field for it in the form and the user was not allowed to change its value. I hope you now understand the problem! So, we need a way to tell Propel that the user cannot update the is_admin column. Do we? Does this information belongs to the model layer? I don't think so.

And since this Rails post was published, a lot of people have tried to find solutions, but none of them seem to really fix the issue. Some solutions are quite ugly but most of them only work on simple examples.

Why do I think Rails developers won't find a definitive solution? Because forms in Rails are not first-class objects. So, the best solutions are based on some configuration you need to make in your models or in your controllers. But, as forms are not first-class objects in Rails, they need to adopt either a white list or a black list strategy. It means that the developers need to list the fields that can be updated from a form, or list the fields that are protected. But you cannot configure this list in the model, because you can have different forms with different security configuration based on the same model. In our previous example, administrators can update the is_admin field, whereas users cannot. If you cannot protect your fields in the model, what about doing it in the controllers. It works quite well for simple examples, but becomes quite ugly and tedious if you have deep nested forms.

Forms in symfony are first-class objects. So, symfony knows the fields you have in your forms. By default, symfony will throw an error if you try to inject a field, or it can also just filter all extra fields. This is possible thanks to two sfForm options: allow_extra_fields and filter_extra_fields. You can read more on these options in the symfony forms book.

Published in