28

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

实现这一点的一种非常简单的方法是什么?

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

4

4 回答 4

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

这个问题可能对你有用

于 2012-08-21T12:20:46.073 回答
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);
});
于 2014-02-11T21:03:43.960 回答
1

你应该试试这个片段。Symfony 表单应该生成特殊的 _csrf_token 应该与 post 请求一起发送。如果没有此值,将引发安全警报。

当然#targetForm应该被form id和/endpoint替换为目标ajax url

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

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

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

});
于 2012-08-21T12:12:41.173 回答
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 中,您可以更新现有的 token <input>

const token = document.getElementById('_token');
fetch(url, opts)
    .then(resp => resp.json())
    .then(response => {
        if (response.token) {
            token.value = response.token;
        }
    });
于 2021-03-10T16:23:17.250 回答