A simple solution to CodeIgniter CSRF protection and Ajax
Posted: March 16, 2012
Category: CodeIgniter
Tagged: ajax, codeigniter, csrf, pyrocms
We all know that we should enable CSRF protection if we want to make our apps resistent to cross site attacks. But what if we already have an Ajax heavy application with tons of POST requests? Do we want to go through the app and add code to each Ajax request? I don't. Here's a simple solution if you are using jQuery.
First the basics
You can read more about this with a quick Google search but here's a crash course: CodeIgniter sets a cookie with a hash as a value. Then when the page is loaded the form_open() helper adds a hidden input to your forms that contains the same value. When the form is submitted by the visitor that hidden input is compared with the cookie value. If they do not match the request is rejected before it ever reaches your controller. This keeps malicious users from submitting a request to your controller from outside your site, possibly by redirecting your own logged in browser.
Traditionally the solution is to read the cookie value before doing an Ajax request and then send it along. This works fine unless you have numerous places to add the code or if you are building an extendable system and other developers may not know how to solve this problem in their own code.
Now the solution
jQuery has the perfect tool for this job: $.ajaxSetup. You can read all about it here: jQuery documentation. $.ajaxSetup allows us to pass data along with every request so it is the perfect fit for sending our CSRF token. All post data from Ajax functions throughout your application will be merged with the data set by $.ajaxSetup. As far as they are concerned the CSRF token doesn't exist. The only thing needed for this to work is jQuery and the Cookie plugin. You can download the cookie plugin from here.
Where's the code?
$(function($) {
// this bit needs to be loaded on every page where an ajax POST may happen
$.ajaxSetup({
data: {
csrf_test_name: $.cookie('csrf_cookie_name')
}
});
// now you can use plain old POST requests like always
$.post('site.com/controller/method', { name : 'Jerel' });
});
Now if you did var_dump($_POST) in your controller at "site.com/controller/method" you would see "Jerel" and the csrf token (something like 3a92ba230fd952a2bcd6faa311b07015).
Any catches?
Only one that I know of. It appears that the BlueImp uploader will not inherit the data from $.ajaxSetup so you will have to pass the cookie value manually in BlueImp as part of its data. I'm not entirely sure why this is as their documentation states that it uses jQuery's $.ajax. If you have an explanation let me know.

Comments
Gustavo Rod Baldera
March 18, 2012
In the upcoming Codeigniter 3.0 (now in development) there is an option in the config.php: 'csrf_regenerate' = Regenerate token on every submission, that you should set to FALSE specially if you are using jQuery autocomplete plugin, because the token verification will fail on several request.
Tony Dew
October 22, 2012
Thanks Jerel! This post just saved my sanity. +1000 internets to you.
Jerel
October 22, 2012
Glad you found it useful :)
Axel Jensen
October 29, 2012
You da man!
thanks a ton!
Lev
January 05, 2013
Someone could change the names of csrf cookies. I use this code for codeigniter projects:
$.ajaxSetup({ data: { <?php echo $this->config->item('csrftokenname'); ?>: $.cookie('<?php echo $this->config->item('csrfcookiename'); ?>') } });
IsaĆas
January 14, 2013
thank you :D :D :D :D
Gavin
June 14, 2013
Such an elegant way to fix this.. great tutorial this saved me some time! You have a new subscriber!