我正在尝试在Symfony 2项目中实现一些ajax功能。使用jquery' $ .post我想将一些数据发送回我的控制器。但是,当我只发布数据时,没有CSRF保护,因为symfony的csrf保护似乎只适用于表单。
实现这个目的的方法是什么?
使用表单时,我可以执行$ form-> isValid()来查明CSRF令牌是否通过。我目前正在将所有想要POST的内容放在一个表单中然后发布。这基本上意味着我只使用该表单来实现CSRF保护,这看起来很糟糕。
答案 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;
}
});