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.
Every single post in this blog confirms how good was my decision to choose symfony one year ago. Keep the good work sf team :)
symfony1.0 is vulnerable, right?
@zero0x - I'm not sure if you're joking or not.... the framework itself isn't vulnerable. This is such a blindingly obvious mistake! Never rely on fromArray() like that, unless you have fully sanitized what you're passing it.
Again a big thank you Fabien and the symfony team for this powerful Form API.
I spent many nights transforming my old 1.0 app to 1.1 and the new forms, and I don't regret a second.
It's some initial work and understanding that has to be done, but the result is simply a set of super maintainable form classes.
Thank you!!!
I am grateful for your effort. I think the symfony form framework is simple, powerful and beautiful.
But I'm concerned about XSS vulnerability in the error messages.
For example in a configure method:
In this case, a message user inputs won't be escaped. Are there any solutions?
Thank you!!
This is a nice little interesting post Fabien. Thanks for sharing.
@Toc: thanks for the report. This issue has been fixed (http://www.symfony-project.org/blog/2008/10/03/symfony-1-1-4-released-security-fix)
Thanks for the swift response! It really moved me! symfony is the best!!
Have a nice weekend and take a good rest.
Because the security must be taken seriously, I think that we aren't full protected against CSRF. The form framework protect in forms, but in the rest of the actions?
I have done a plugin for this, and maybe it can inspire you to build it in core framework.
http://trac.assembla.com/pablodip/browser/plugins/pdCSRFPlugin/trunk
And of course, protect the admin generator, that currently it aren't protected.
As Ian says, we shouldn't use fromArray or this kind of generic update function until we are sure we have sanitized values. In 1.0 i remember that i was using a simple sanitize function in order to keep only values of allowed fields.
It's seems to be quite safe against mass assignment vulnerability! Is it right?