【问题标题】:Require the presence of an X-CSRF-Token header in all requests要求在所有请求中都存在 X-CSRF-Token 标头
【发布时间】:2014-04-11 08:53:37
【问题描述】:

Symfony 中默认的 CSRF 预防是基于表单的(如果您使用提供的表单构建器,这会自动发生)。但是,对于 AJAX 请求,手动将 CSRF 令牌附加到每个 HTTP 请求,然后为每个请求手动检查它是很繁琐的。

按照this question 的 cmets 中的建议,将令牌嵌入为 HTTP 标头是一个不错的方法。然后可以将 jQuery 配置为在每个请求中将此标头包含为 described here

我的问题是如何在 Symfony 中最好地处理这个问题?我可以使用 Twig 在每个页面中包含 CSRF 令牌,但是如何检查传入请求以确保每个请求的标头中都包含有效的令牌?

我知道如何在控制器中使用$request->headers->get('X-CSRF-Token') 访问 HTTP 标头,但这仍然意味着必须在每个控制器中单独执行此检查。我应该在哪里添加此检查以便尽早发现它?

【问题讨论】:

  • 您可以使用 kernel.request 事件在处理响应之前进行检查。见symfony.com/doc/current/book/…
  • Ghassen,是的,这听起来很像我想要完成的事情。我应该在 Symfony 的什么地方包含处理 kernel.request 事件的代码,以便我可以检查是否存在标头,然后继续正常处理响应?
  • 今晚我出去了,但如果你有耐心,我明天会给你一个完整的例子,同时你可以谷歌 symfony2 事件调度器组件,以更好地了解如何实现事件挂钩

标签: php symfony http-headers csrf


【解决方案1】:

对此我不是 100% 确定,但我会使用 BaseFormType 并对其进行扩展。

您的基本表单类型将使用表单事件 PRE_SET_DATA 侦听器并根据请求查找标头,然后将该标头填充到 _token 字段中。

//FormType
class BaseFormType extends AbstractType
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $request = $this->request;
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use($request){
            $token = $request->headers->get('X-CSRF-Token');
            if($token){
                $form = $event->getForm();
                $form->get('_token')->setData($token);
            }
        }
    }
}

那么你所有的 FormTypes 都会扩展这个:

//YourCustomFormType
class YourCustomFormType extends BaseFormType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm();
        $form->add('name');
    }
}

然后你的控制器动作

//Controller
public function sayMyNameAction(Request $request)
{
    $name = new Name();
    $form = $this->createForm(new YourCustomFormType($request),$name);
    if($request->isMethod('POST'))
    {
        $form->handleRequest($request);
        if($form->isValid()){
            return new JsonResponse(array('say':$name->getName()));
        }
    }
}

或者类似的东西。

【讨论】:

    猜你喜欢
    • 2016-03-29
    • 2021-03-18
    • 2014-02-03
    • 2021-02-17
    • 1970-01-01
    • 2018-12-14
    • 2018-03-16
    • 2011-11-15
    • 2016-09-09
    相关资源
    最近更新 更多