[英]Codeigniter ajax CSRF problem
我做了一個簡單的自動加載功能,當你在網站上向下滾動時加載內容。 但是,當我在Codeigniter中啟用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++;
});
}
}
});
}
由於Codeigniter期望在所有POST請求中都有TOKEN,因此當CSRF啟用時,我無法使其工作。 有什么建議?
啟用CSRF時出錯
無法加載資源:服務器響應狀態為500(內部服務器錯誤)
如果我關閉CSRF,一切都很好......
您可能想嘗試我使用過的代碼。 它很棒:
<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>
正如其他人所說 - 你必須使用AJAX請求參數發布CSFR令牌名稱及其值。 這是一個簡單的解決方案,可以自動將其附加到每個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
});
});
如果需要,您可以在適當的位置回顯令牌名稱和哈希值。 像這樣的東西。
echo $this->security->get_csrf_token_name()
和
echo $this->security->get_csrf_hash()
或者,您可以像往常一樣使用form_open()並使用從javascript為您生成的隱藏輸入。 禁用CSRF功能是錯誤的方法。
在審查了我的情況后,我認為最好的選擇是使用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'));
以前的建議很有效,但我發現使用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版本)
上面幾個答案的唯一問題是csrf令牌僅對一個請求有效,所以如果你通過ajax發出一個帖子請求並且不刷新頁面你就不會有你下一個ajax帖子的當前csrf令牌請求。 這是我的解決方案:
在您的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)));
$ data =要返回瀏覽器的數據
$ csrf =瀏覽器用於下一個ajax post請求的新csrf標記
顯然你可以用其他方式輸出它,但JSON主要用於ajax調用。 還要在每個帖子響應中包含此標記,以用於下一個帖子請求
然后在你的下一個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
,其中包含你在crf_token
/ config / config.php中找到的令牌的名稱, crf_token
包含$config['csrf_token_name'] = 'csrf_token';
基本上你需要做的是從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 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.