gilvandev
gilvandev

Reputation: 109

Ajax call crash on CodeIgniter - CSRF Error 403

I'm trying to perform Ajax calls within CodeIgniter. As had already searched before, when the CSRF protection is active, a hash (randomly generated) must be submitted with each request to the server.

In research I found the following code to always hash to be sent along with the other data through the Ajax request:

$.ajaxSetup({
    data: {
        arquivo_facil_tk: $.cookie('arquivo_facil_co')
    }
});

So I got a positive result on the first call right after the page is loaded. But to attempt a second call, get the error 403. I also found the option of adding this code snippet for each Ajax call I make, but as my software performs several calls, it becomes unfeasible and rude.

How could I fix this? Also tried using the beforeSend event but got the same error.

Upvotes: 1

Views: 2472

Answers (3)

Marcelo Agimóvel
Marcelo Agimóvel

Reputation: 1719

I was with the same problem. The solution? I use one CSRF token in entire system, only changing at login/logout (and similar functions).

To avoid several submits from same form (like a double click or even an attack), when I call the form, I also insert a random ID on a transaction table.

When I receive this form, I check for the ID in transaction table. If exist's, do action and erase ID from transaction table. If it doesn't, show message error.

Upvotes: 0

OGZStudio
OGZStudio

Reputation: 17

The problem is that the csrf token is only valid for one call, so if you want to use ajax on another post request without refreshing the page you need to somehow get the new token without the form being reloaded. You can do this in your codeigniter controller by sending the new token back to the requesting script.

In your CodeIgniter Controller:

$data = array('data'=> 'data to send back to browser');
$csrf =  $this->security->get_csrf_hash();
$this->output
    ->set_content_type('application/json')
    ->set_output(json_encode(array('data' => $data, 'csrf' => $csrf)));

$data = the data to return to the browser

$csrf = new csrf token to be used by the browser for next ajax post request

Obviously you can output this in other ways but JSON is used mostly with ajax calls. Also include the token this way in every post response to be used for the next post request

Then in your next ajax request (javascript):

var token = data.csrf;

$.ajax({
    url: '/next/ajax/request/url',
    type: 'POST',
    data: { new_data: 'new data to send via post', csrf_token:token },
    cache: false,
    success: function(data, textStatus, jqXHR) {
        // Get new csrf token for next ajax post
        var new_csrf_token = data.csrf     
       //Do something with data returned from post request
    },
    error: function(jqXHR, textStatus, errorThrown) {
      // Handle errors here
      console.log('ERRORS: ' + textStatus + ' - ' + errorThrown );
    }
});

Also remember that where I've got csrf_token:token replace crf_token with the name of your token found in application/config/config.php on line that states $config['csrf_token_name'] = 'csrf_token';

Upvotes: 0

Daniel Waghorn
Daniel Waghorn

Reputation: 2985

Rather than using ajaxSetup simply include the CSRF token along with the data in your actual AJAX call like so:

data: {var: value, arquivo_facil_tk: $.cookie('arquivo_facil_co')}

or if you're serializing forms simply:

data: $(this).serialize() + '&arquivo_facil_tk=' + $.cookie('arquivo_facil_co')

Upvotes: 1

Related Questions