Codeigniter CSRF valid for only one time ajax request

我怕爱的太早我们不能终老 提交于 2019-11-27 06:44:45

问题


I want to upload image on the server on change event of jQuery but using codeigniter csrf I am able to upload image only one time. How can I upload images using ajax for multiple requests.Please keep in mind when I set this

config['csrf_protection'] = FALSE;

then I am able to send multiple request jQuery onchange event but when csrf_protection is going to be false then I think there is no advantage of csrf. so the question is how can I send multiple requests using ajax while csrf_protection is enable. My jquery code is following

$("#avatar").change(function(){
    var link = $("#avatar").val();     
    $.ajax({
        url : "<?php echo base_url('main/test'); ?>",
        type: 'post',
        data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>',"id":"hello","link":link},            
        success : function(data)
        {   
            alert(data);
        }  
    });
});

回答1:


In my opinion you should try to recreate your csrf token each request

Try this code example...

For the js funcion

var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
    csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
("#avatar").change(function(){
    var link = $("#avatar").val();

    var dataJson = { [csrfName]: csrfHash, id: "hello", link: link };

    $.ajax({
        url : "<?php echo base_url('main/test'); ?>",
        type: 'post',
        data: dataJson,            
        success : function(data)
        {   
            csrfName = data.csrfName;
            csrfHash = data.csrfHash;
            alert(data.message);
        }  
    });
});

and for the controller

public function test() { 
    $config['upload_path'] = './uploads/'; 
    $config['allowed_types'] = 'gif|jpg|png'; 
    $config['max_size'] = 500; 
    $config['max_width'] = 260; 
    $config['max_height'] = 260; 

    $reponse = array(
                'csrfName' => $this->security->get_csrf_token_name(),
                'csrfHash' => $this->security->get_csrf_hash()
                )

    $this->load->library('upload', $config); 
    if (!$this->upload->do_upload('link')) { 
        $reponse['message'] = "error"; 
    } 
    else { 
        $data = array('upload_data' => $this->upload->data()); 
        $image_name = $data['upload_data']['file_name']; 
        $reponse['message'] = $image_name; 
    } 

    echo json_encode($reponse);
}

Let me know and good luck

Note: When someone ask you for posting more data to the question, don't post it as a comment or answer, it's better to edit the question itself and adding the stuff




回答2:


You can set this in config.php

$config['csrf_regenerate'] = FALSE;

so the csrf protection is valid during all the session time it will solve your problem. If you set $config['csrf_regenerate'] = true; then CI generate new csrf token every request so your old csrf token not match with new generated csrf token




回答3:


$config['csrf_regenerate'] = TRUE;

keep auto generate to true it will be more safer. In similar case when csrf is expired in first request. What i have implemented

$(document).ajaxComplete(function (event, xhr, settings) {
 let response = xhr.responseText,
 let obj = JSON.parse(response),
 let csrfData = obj.csrf;
 document.querySelector('input[name="' + csrfData.name + '"]').value = csrfData.hash; 
}); //Also here you can update any other non input element    

In every ajax response we are passing csrf data in which latest csrf data will be replaced with current one

Sample response from request

{ 
csrf : {
  name : 'csrf_name',
  hash : 'qw76sd7s6f78sdfs8dfs9df8cx9'
 }
}

I update csrf token in every ajax request. Also don't choose this method if you are working with multi tab environment




回答4:


All you need to do is reload the CSRF token in your AJAX response. It is that simple!.




回答5:


add this at a js file which is loaded every page (I put this at the end of jquery.js )

    $.ajaxSetup({
        beforeSend:function(jqXHR, Obj){
            var value = "; " + document.cookie;
            var parts = value.split("; csrf_cookie_name=");
            if(parts.length == 2)   
            Obj.data += '&csrf_token='+parts.pop().split(";").shift();
        }
    });

(notice that in every ajax request you can not have empty data to send)

"csrf_cookie_name" at top defined in config.php

$config['csrf_cookie_name'] = 'csrf_cookie_name';



回答6:


Please try like my code. its working my application

your view file

$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();

<input type="text" id="search-text" name="parent_name" placeholder="Search" value=""  >
<input type="hidden" id="csrf" name="<?php echo $token_name; ?>" value="<?php echo $token_hash; ?>" />

after set jquery post method like below

// Get Keyup 
jQuery( "#search-text").keyup(function() {
    // Get Data 
    var val       = jQuery("#search-text").val();
    var hashValue = jQuery('#csrf').val();

    // Get jquery post for ajax task
    jQuery.post( 
        '<?php echo $base_controler; ?>',
        {val:val,'<?php echo $this->security->get_csrf_token_name(); ?>':hashValue}, 
        function(data)
        { 
            // Get return data to decode
            var obj = jQuery.parseJSON(data);
            // Get csrf new hash value
            var new_hash = obj.csrfHash;
            // Set csrf new hash value update
            jQuery('#csrf').val(new_hash);

        }
    );        

});

please set your controller like below

$reponse = array(
        'csrfName' => $this->security->get_csrf_token_name(),
        'csrfHash' => $this->security->get_csrf_hash()
        );
echo json_encode($reponse);

above all code recreate your csrf token each request.




回答7:


Each time you make a request, the csrf_token is being updated by CI. That's why the CSRF only work once. So everytime we make a request we need to update the csrf_token too. I solve this problem by doing this.

Conroller: get the updated csrf using this code.

public function update_csrf()
{
  $data['csrf_hash'] = $this->security->get_csrf_hash();
  echo json_encode($data);
}

AJAX: replace the old value of your csrf name="csrf_token_name"

var jqXHR = $.ajax({
            url: $(this).attr('action'),
            type: 'POST',
            data: $(this).serialize(),
            dataType: 'json',
        })
        jqXHR.done(function(response) {
            $('input[name=csrf_token_name]').val(response.csrf_hash); //update the csrf to the form 
        })
        jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR);
            console.log(textStatus);
            console.log(errorThrown);
        });

Important!: use dataType: 'json'

So now each time you have a successful request, the csrf_token is updated too and you are now free from 403 (Forbidden) error.




回答8:


Edit the config:

$config['csrf_exclude_uris'] = ['controller/method'];

Array can include all whitelisted controllers/methods you want the csrf protection to be disabled for.

The array can also handle regular expressions such as:

$config['csrf_exclude_uris'] = array(
                                        'api/record/[0-9]+',
                                        'api/title/[a-z]+'
                                );

For more information visit Codeigniter Documentation - Security Class



来源:https://stackoverflow.com/questions/38502548/codeigniter-csrf-valid-for-only-one-time-ajax-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!