2011-09-08 125 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'));