Symfony CSRF和Ajax

时间:2012-08-21 12:04:47

标签: ajax symfony csrf

我正在尝试在Symfony 2项目中实现一些ajax功能。使用jquery' $ .post我想将一些数据发送回我的控制器。但是,当我只发布数据时,没有CSRF保护,因为symfony的csrf保护似乎只适用于表单。

实现这个目的的方法是什么?

使用表单时,我可以执行$ form-> isValid()来查明CSRF令牌是否通过。我目前正在将所有想要POST的内容放在一个表单中然后发布。这基本上意味着我只使用该表单来实现CSRF保护,这看起来很糟糕。

4 个答案:

答案 0 :(得分:27)

在Symfony2中,CSRF令牌默认基于会话。如果你想生成它,你只需要获得这个服务和调用生成方法:

//Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider by default
$csrf = $this->get('form.csrf_provider');
//Intention should be empty string, if you did not define it in parameters
$token = $csrf->generateCsrfToken($intention); 

return new Response($token);

This question可能对您有用

答案 1 :(得分:2)

我间歇性地遇到了这个问题。原来这不是因为我的ajax,而是因为Silex给你一个弃用的DefaultCsrfProvider,它使用会话ID本身作为令牌的一部分,我为了安全而随机更改了ID。相反,明确告诉它使用新的CsrfTokenManager修复它,因为那个生成一个令牌并将其存储在会话中,这样会话ID可以改变而不会影响其有效性。令牌。

/** Use a CSRF provider that does not depend on the session ID being constant. We change the session ID randomly */
$app['form.csrf_provider'] = $app->share(function ($app) {
    $storage = new Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage($app['session']);
    return new Symfony\Component\Security\Csrf\CsrfTokenManager(null, $storage);
});

答案 2 :(得分:1)

您应该尝试使用此代码段。 Symfony表单应该生成特殊的_csrf_token,它应该与post请求一起发送。如果没有此值,将引发安全警报。

当然#targetForm应该由目标ajax url替换为表单id和/ endpoint

$('#targetForm').bind('submit', function(e) {

    e.preventDefault();
    var data = $(this).serialize();

    $.post('/endpoint', data, function(data) {
        // some logic here
    });

});

答案 3 :(得分:0)

在 Symfony 4+ 中,您可以直接在控制器或操作或任何地方使用依赖注入,例如,如果您正在提交表单并希望刷新同一表单的令牌,则 $tokenId 是 FQDN表单类型类:

namespace App\Controller;

use App\Form\MyFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

class MyController extends AbstractController
{
    public function submit(CsrfTokenManagerInterface $tokenManager): JsonResponse
    {
        // ...
        $token = $tokenManager->refreshToken(MyFormType::class);
        return new JsonResponse(['token' => $token->getValue()]);
    }
}

在您的 JavaScript 中,您可以更新现有令牌 <input>

const token = document.getElementById('_token');
fetch(url, opts)
    .then(resp => resp.json())
    .then(response => {
        if (response.token) {
            token.value = response.token;
        }
    });