在 Symfony 中防止 "Overposting Forms"

Protect against "Overposting Forms" within Symfony

过度post表单是操纵数据/入侵网站的一种常见方式。 该可能的安全问题的原因是 Form/Model Binder,它会自动将 Form 绑定到对象。在 ASP.NET 内,我知道如何防范此类攻击。

我们有一个用户模型,包含以下字段:ID、名字、姓氏、密码。我希望用户能够更改他的名字和姓氏。 正如我们所知,这发生在 Symfony(和 ASP.NET MVC)中,带有一个 Form/Model Binder,它接受表单的 "names" 并将这些值映射到相应的对象字段。

ASP.NET 中的解决方案,在每个 "Post-Controller" 上使用 [Bind] 表达式:

public async Task<ActionResult> Create([Bind(Include="FirstName,Lastname")] Employee employee)

如何在 Symfony 应用程序中防止这种攻击?如何告诉 Model/Form 活页夹,哪些 post 数据应该只被接受/预期?

@编辑: 这个问题旨在了解在将 FormType 用于多个用例时如何解决此类问题,例如用于创建和编辑员工。我知道一般来说,Symfony 表单组件已经检查是否有任何额外的字段。

如果您对 symfony 表单使用食谱(阅读:正常)方法,那么您已经拥有该保护以及 CSRF 保护。

如果您向请求添加额外的字段,您将收到以下错误:

This form should not contain extra fields

示例表格:

class FooType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('title');
        //Class Foo also has a text attribute
    }
}

您将在控制器中使用上述 class 创建编辑或创建表单,并且只能修改添加到构建器的字段。这样 Foo::$text 就不能使用表单修改了。

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';
    }
}

不需要额外的事件,因为这会有点矫枉过正。

控制器:

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
    ));
}

Bonus