403 Forbidden Access to CodeIgniter controller from ajax request

18,154

Solution 1

Remove the <code> and application/controller from your ajax_processor like,

var ajax_processor = 'http://localhost/patientcare-v1/index.php/ajax_porcessor/save_physical_info';

If you are hiding index.php from url by using htaccess or routing then try this url,

var ajax_processor = 'http://localhost/patientcare-v1/ajax_porcessor/save_physical_info';

Solution 2

CodeIgniter use csrf_protection, you can use it with Ajax and JQuery simply. This (ultimate ?) solution work on multiple Ajax request (no 403 ;-) and preserve the security).

Change the configuration

Open the file /application/config/config.php and change the line $config['csrf_token_name'] by :

$config['csrf_token_name'] = 'token';

You can use another name, but change it everywhere in future steps.

Add CSRF in your Javascript

Add script in a view; for me is in footer.php to display the code in all views.

<script type="text/javascript">
    var CFG = {
        url: '<?php echo $this->config->item('base_url');?>',
        token: '<?php echo $this->security->get_csrf_hash();?>'
    };
</script>

This script create an object named CFG. This object can be used in your Javascript code. CFG.url contain the url of your website and CFG.token ... the token.

Automatically renew the CSRF

Add this code in your part $(document).ready(function($){---}) as

$(document).ready(function($){
    $.ajaxSetup({data: {token: CFG.token}});
    $(document).ajaxSuccess(function(e,x) {
        var result = $.parseJSON(x.responseText);
        $('input:hidden[name="token"]').val(result.token);
        $.ajaxSetup({data: {token: result.token}});
    });
});

This script initialize the CSRF token and update it everytime when a request Ajax is sended.

Send the CSRF in PHP

I've created a new controller, named Ajax. In CodeIgniter, the link to use it is http://www.domain.ltd/ajax/foo

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Ajax extends CI_Controller {

    public function foo() {
        $this->send(array('foo' => 'bar'));
    }

    private function send($array) {

        if (!is_array($array)) return false;

        $send = array('token' => $this->security->get_csrf_hash()) + $array;

        if (!headers_sent()) {
            header('Cache-Control: no-cache, must-revalidate');
            header('Expires: ' . date('r'));
            header('Content-type: application/json');
        }

        exit(json_encode($send, JSON_FORCE_OBJECT));

    }

}

The send function add the CSRF automatically and transform an array in object.

The final result

Now, you can use Ajax with JQuery very simply !

$.post(CFG.url + 'ajax/foo/', function(data) {
    console.log(data)
}, 'json');

Result :

{"token":"8f65cf8e54ae8b71f4dc1f996ed4dc59","foo":"bar"}

When the request get data, the CSRF is automatically updated to the next Ajax request.

Et voilà !

Share:
18,154
JCm
Author by

JCm

An experienced IT professional with very wide experience in Software Development, Business Intelligence and Data Analytics, Computer Networking, Linux and Windows Server Management and Administration, Relational Database Mgt Systems, and Telecommunications Technologies. I'm also proficient in full stack web application development and in business automation using application APIs, python and bash shell scripting.

Updated on June 05, 2022

Comments

  • JCm
    JCm almost 2 years

    Im having trouble with sending an ajax request to codeigniter controller. It is throwing back a 404 Forbidden Access error. I have found some sort of similar question to this but im not sure if its particular to CodeIgniter framework, and also the solution give in that thread did not solve my problem. below is my ajax request. Im wondering this is probably because of the .htaccess of the root folder of CI Application folder, but i dont want to change its default configuration yet.

    Is sending ajax request to CI controller the correct way of implementing this? if not, any suggestion please. Thanks!

    var ajax_load = '{loading gif img html}';
    var ajax_processor = 'http://localhost/patientcare-v1/application/controller/ajax_processor/save_physical_info';
    
    $("#save").click(function(){
        $("#dialog-form").html(ajax_load);
        $.post(
            ajax_processor,
            $("#physical-info").serialize(),
            function(responseText){
                $("#dialog-form").html(responseText);
            },
            "json"
        );
    });
    
  • JCm
    JCm about 10 years
    <code> tag was just for the formatting in asking the question. already corrected it.
  • qwertzman
    qwertzman over 7 years
    I love your solution and I'd like to add that when using the same page using AJAX in multiple tabs than that will still cause issues. The only way for me to circumvent that was to disable regeneration for those controllers. CSRF regen seems useless anyway, been reading up on that. cheers.