Overposting a form is a common way of manipulating data / hacking a site. The cause for that possible security problem is the Form/Model Binder, that automatically binds a Form to an object. Within ASP.NET, I know how to protect against these sort of attacks.
We have a User Model, with the following fields: ID, Firstname, Lastname, Password. I want the user to be able to change his Firstname and Lastname. As we know, this happens within Symfony (and ASP.NET MVC) with a Form/Model Binder, that takes the "names" of the forms and maps these values to the corresponding object fields.
Solution in ASP.NET, using the [Bind] expression on each "Post-Controller":
public async Task<ActionResult> Create([Bind(Include="FirstName,Lastname")] Employee employee)
How can I prevent this kind of attack within a Symfony application? How to tell the Model/Form binder, which post data should only be accepted / expected?
@Edit: This question intended to know how to solve this kind of problem when using a FormType for multiple usecases, e.g. for Creation and Edit of an employee. I know that in general, Symfony Form Component already checks if there are any additional fields.
class FooType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['type'] === 'edit') {
$builder->add('editMe');
//More edit me fields
}
$builder->add('createMe');
//more create me fields
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired(array(
'type'
));
$resolver->setDefaults(array(
'type' => 'create'
));
}
//For consistency
public function getName()
{
return 'foo';
}
}
There is no need for extra events since it would be an overkill.
Controller:
public function createFooAction(Request $request)
{
$form = $this->createForm(new FooType(), new Foo());
$form->handleRequest($request);
if ($form->isValid() && $form->submitted()) {
//flush form
}
return $this->render("AppBundle:Foo:create.html.twig", array(
'form' => $form
));
}
public function editFooAction(Request $request, $id)
{
$foo = ... //find($id)
$form = $this->createForm(new FooType(), $foo, array(
'type' => 'edit'
));
$form->handleRequest($request);
if ($form->isValid() && $form->submitted()) {
//flush form
}
return $this->render("AppBundle:Foo:edit.html.twig", array(
'form' => $form
));
}
If you use the cookbook (read: normal) approach to symfony forms, you already have that protection, alongside with CSRF protecttion.
If you add an extra field to the request you will get the following error:
This form should not contain extra fields
Example Form:
class FooType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
//Class Foo also has a text attribute
}
}
You will create an edit or create form using the above class in your controller and only the fields added to the builder can be modified. This way Foo::$text can not be modified using the form.