2011-09-08 127 views
7

我做了一个简单的自动加载功能,当您在网站上向下滚动时加载内容。但是,在Codeigniter中启用CSRF保护时,似乎存在一些问题。Codeigniter ajax CSRF问题

我没有使用表单,所以我不知道我可以如何从A发送令牌给B,当我在滚动时执行我的发布请求。

我的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++; 
       }); 
      } 
     } 
    }); 
} 

因为笨预计所有POST请求我不能让这时候CSRF我能工作的令牌。有什么建议么?

错误时CSRF是启用

无法加载资源:服务器500(内部服务器错误)的状态

如果我把CSRF关闭,一切都很正常回应..

回答

10

如果你愿意,你可以在适当的地方回显令牌名称和散列。像这样的东西。

echo $this->security->get_csrf_token_name() 

echo $this->security->get_csrf_hash() 

或者,你可以使用form_open()像往常一样,并使用为您从您的JavaScript生成隐藏的输入。禁用CSRF功能是错误的方法。

0

基本上,您需要做的是从cookie中获取预期的csrf值(默认情况下命名为'ci_csrf_token'),然后将其与其他数据一起发布。

您将需要修改此行:

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

到:

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

可能需要安装插件的cookie(我真的不知道,我用的mootools)。以下是更多信息:http://aymsystems.com/ajax-csrf-protection-codeigniter-20

12

您可能会喜欢尝试我使用过的这段代码。它很好用:

<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> 
12

正如别人所说 - 你必须发布CSFR令牌名称及其值与AJAX请求参数。这是一个简单的解决方案,可以自动将其附加到每个AJAX请求。

这里是我把我的主视图,因此,这段代码的每一页上加载其他JavaScript文件之前:

<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> 

这里是一个JavaScript文件的一部分,我包括在每一页上:

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

很容易的解决方案..为我工作:)感谢@georgiar –

+0

真的感谢为我工作 –

0

上建议工作的伟大,而不是使用,你可以在每一个数据后施加可变的,我觉得很简单,使用Ajax的设置此令牌自动应用到每一个岗位:

$(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(); ?>'; 
    }); 

(适用于jquery-1.9.1。我不确定其他jQuery版本)

0

上述答案中的一小部分的唯一问题是,一个csrf标记只对一个请求有效,所以如果你通过ajax发出一个post请求并且不刷新该页面将不会有您当前的csrf标记用于您的下一个ajax发布请求。这是我的解决方案:

在你的CodeIgniter控制器:

$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))); 

$数据=返回到浏览器

$ CSRF =新CSRF令牌将数据发送到浏览器的下一个AJAX使用post request

显然你可以用其他方式输出这个,但是JSON主要用于ajax调用。还包括此令牌在每一个岗位应被用于下一个POST请求

然后在你的下一个Ajax请求(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); 
    } 
}); 

还记得,我已经得到了csrf_token:token与替换crf_token在应用程序/配置/ config.php文件发现在网上您的令牌,指出$config['csrf_token_name'] = 'csrf_token';

0

的名字在审查我的情况,我相信最好的选择是使用CSRF但重置每次尝试令牌。否则,早先表达的关于重新使用cookie令牌的想法将允许攻击者使用破坏该对象的同一令牌重新提交数据数百次。

因此我创建了以下功能:

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(); 
} 

举例来说,如果一个基于AJAX的登录表单失败 - 调用你的PHP这个功能,然后在接收失败(该解决方案使用JavaScript端然后jQuery和从W3Schools的一个的getCookie函数)将只需拨打:

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