开发者

Codeigniter ajax CSRF problem

I've made a simple autoload function that loads content when you scroll down on a website. However, there seems to be a few problems when i enable CSRF protection in Codeigniter.

I'm not using a form, so i don't know how i can send the token from A to B when i'm doing my post request as you scroll.

My JavaScript

if (location.href == baseurl) {
    $(window).scroll(function(){
        if ($(window).scrollTop() > $('body').height() / 2) {
            if(doScroll == 1) {
                $.post(baseurl + 'ajax/images',{'id' : ID}, function(data) {
                    $("#wrapper_content").append(data);
                    if(data == 'Det finnes ikke flere bilder i databasen, WTF!? Send inn forslag ASAP!') {
                        doScroll = 0;
                    }
                    ID++;
                });
            }
        }
    });
}

Since Codeigniter expects a TOKEN on all POST request i can't get this to work when CSRF i enabled. Any suggestions开发者_开发百科?

Error when CSRF is Enabled

Failed to load resource: the server responded with a status of 500 (Internal Server Error)

If i turn CSRF off, everything works great...


You might like to try this code I've used. It works great:

<script type="text/javascript">
$(function(){
   $('.answerlist').each(function(e){

  $(this).click(function(){

    var valrad = $("input[@name=answer]:checked").val();


    var post_data = {
        'ansid': valrad,
        '<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
    };

        $.ajax({
                type: "POST",
                url: "<?php echo base_url(); ?>online/checkanswer",
                data: post_data,
                success: function(msg){
                  /// do something 
                }
            });

  });

   });


});


</script>


As others say - you have to post the CSFR token name and its value with the AJAX request parameters. Here is a simple solution to append it automatically to every AJAX request.

Here is what I put on my main view, so this code is on every page before loading the other javascript files:

   <script>
     var csfrData = {};
     csfrData['<?php echo $this->security->get_csrf_token_name(); ?>']
                       = '<?php echo $this->security->get_csrf_hash(); ?>';
   </script>
   <!-- ... include other javascript files -->
  </body>
</html>

And here is a part of a javascript file that I include on every page:

$(function() {
    // Attach csfr data token
    $.ajaxSetup({
       data: csfrData
    });
});


If you want, you can echo both the token name and the hash somewhere appropriate. Something like this.

 echo $this->security->get_csrf_token_name()

and

 echo $this->security->get_csrf_hash()

Or, you could use form_open() as usual and use the hidden input that is generated for you from your javascript. Disabling the CSRF-functionality is the wrong way to go.


Having reviewed my situation I believe the best option is to use CSRF but reset the token on each attempt. Otherwise the ideas expressed earlier about re-using the cookie token would allow an attacker to resubmit data hundreds of times using the same token which defeats the object of the point.

As such I have created the following function:

public function resetCSRF(){    

    $this->security = null;

    $_COOKIE[$this->config->item('csrf_cookie_name')] = null;

    load_class('Security', 'core');

    $this->security->csrf_set_cookie();

return $this->security->get_csrf_hash();
}

If for example an ajax based login form fails - call this function in your PHP and then on the javascript side that receives the failure (this solution uses Jquery and a getCookie function from w3schools) would then simply call:

$('input[name="csrf_test_name"]').val(getCookie('csrf_cookie_name'));


Basically what you need to do is get the expected csrf value from the cookie (named 'ci_csrf_token' by default), then post it along with your other data.

You would need to modify this line:

$.post(baseurl + 'ajax/images',{'id' : ID}, function(data) {

to:

$.post(baseurl + 'ajax/images',{'id' : ID,'ci_csrf_token' : $.cookie('ci_csrf_token')}, function(data) {

Might need to install the cookie addon (I'm not really sure; I use mootools). Here is more information: http://aymsystems.com/ajax-csrf-protection-codeigniter-20.


Previous suggestions work great, but rather than using a variable that you can apply in every data-post, I find it simpler to use the ajax-setting to automatically apply this token to every post:

$(document).ajaxSend(function(elm, xhr, s){
        if(s.data){
            s.data += '&';
        }
        s.data += '<?php echo $this->security->get_csrf_token_name(); ?>=<?php echo $this->security->get_csrf_hash(); ?>';
    }); 

(works with jquery-1.9.1. I'm not sure about other jquery-versions)


The only problem with a few of the above answers is that a csrf token is only valid for one request, so if you make a post request via ajax and do not refresh the page you will not have the current csrf token for your next ajax post request. This is my solution:

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 this token 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';

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜