I am trying to implement some ajax functionality in my Symfony 2 project. Using jquery's $.post I want to send some data back to my controller. However, when I just POST the data no CSRF protection is in place, as symfony's csrf protection only seems to apply to forms.
What would be a pretty straightforward way to implement this?
When using forms I can just do $form->isValid() to find out whether or not the CSRF token passes. I am currently placing everything I want to POST in a form and then posting that. Which basically means I am only using that form to implement CSRF protection, which seems hacky.
In Symfony2 CSRF token is based on session by default. If you want to generate it, you just have to get this service and call generation method:
//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 might be useful for you
I had this problem, intermittently. Turned out it was not due to my ajax, but because Silex gives you a deprecated DefaultCsrfProvider
which uses the session ID itself as part of the token, and I change the ID randomly for security. Instead, explicitly telling it to use the new CsrfTokenManager
fixes it, since that one generates a token and stores it in the session, such that the session ID can change without affecting the validity of the token.
/** 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);
});
You should try this snippet. Symfony form should generate special _csrf_token that should be send with post request. Without this value security alert will be raised.
Of course #targetForm should be replaced by form id and /endpoint by target ajax url
$('#targetForm').bind('submit', function(e) {
e.preventDefault();
var data = $(this).serialize();
$.post('/endpoint', data, function(data) {
// some logic here
});
});