CSRF Validation in AJAX With Symfony

From Littledamien Wiki
Revision as of 20:00, 10 February 2015 by Video8 (talk | contribs) (Created page with "Category:Symfony Category:PHP Category:jQuery Category:JavaScript Category:Web Development == Goal == From a Symfony page, submit POST data including a CS...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Goal

From a Symfony page, submit POST data including a CSRF token using jQuery, then validate that CSRF token in the controller that handles the request.

Template

csrf_token() is a built-in Twig template function with Symfony. Normally it's used with forms.

<div class="hidden" id="csrf-token" data-token="{{ csrf_token('') }}"><!-- --></div>

JavaScript/jQuery

  • Bind an ajaxSend handler to the document that will pass along the csrf token in the request headers for every AJAX call.
$(document).bind('ajaxSend', function(elm, xhr, s){
	if (s.type==="POST") {
		var csrf_token = $(lclSettings.selectors.csrf).data('token');
		xhr.setRequestHeader('X-CSRF-Token', csrf_token);
	}
});

Symfony controller

Retrieve the CSRF token from the request headers and validate it in the controller.[1][2]

<syntaxhighlight lang="php"> use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response;

// ...

/** * @Route("/update/completed/{id}", name="_updated_completed") * @ParamConverter("tutorial", class="AppBundle:Tutorial") * @Method("POST") */ public function updateCompletedAction(Request $request, Tutorial $tutorial) { // get the csrf token from the request header $csrf_token = $request->headers->get('x_csrf_token');

// get the object to validate the token $csrf = $this->get('form.csrf_provider');

// validation if ($csrf->isCsrfTokenValid(, $csrf_token)) {

// Handle the request and create a json string for the response } else { // Invalid token $response = new Response(json_encode(array( 'error' => 'Invalid request.' ))); }

// return JSON response $response->headers->set('Content-Type', 'application/json'); return $response; } </syntaxhighlighter>

  • The @ParamConverter annotation causes the id value to automatically be converted into an entity object, but it doesn't have any direct impact on the CSRF logic.
  • The @Method annotation causes only requests using the POST method to be matched. This also doesn't directly impact the CSRF, but it does provide a layer of protection from inspecting the requests.
  • Get the token string from the headers.
  • Get a Symfony CSRF provider object to do the validation.
  • Validate the token and only perform the action if the token is valid.
  • Returns a JSON string to the script that called this action.

Notes