2011-09-08 33 views
7

Tôi đã thực hiện chức năng tự động tải đơn giản tải nội dung khi bạn cuộn xuống trên một trang web. Tuy nhiên, có vẻ như có một vài vấn đề khi tôi bật tính năng bảo vệ CSRF trong Codeigniter.Codeigniter ajax Vấn đề CSRF

Tôi không sử dụng biểu mẫu, vì vậy tôi không biết làm cách nào tôi có thể gửi mã thông báo từ A đến B khi tôi đang thực hiện yêu cầu đăng bài khi bạn cuộn.

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

Kể từ CodeIgniter hy vọng một TOKEN trên tất cả các yêu cầu POST tôi không thể có được điều này để làm việc khi CSRF i kích hoạt. Bất kỳ đề xuất?

Lỗi khi CSRF đã được kích hoạt

Không thể tải tài nguyên: máy chủ đáp lại bằng một tình trạng của 500 (Internal Server Error)

Nếu tôi bật CSRF tắt, mọi thứ hoạt động tốt ..

Trả lời

10

Nếu muốn, bạn có thể lặp lại cả tên mã thông báo và mã băm ở nơi thích hợp. Một cái gì đó như thế này.

echo $this->security->get_csrf_token_name() 

echo $this->security->get_csrf_hash() 

Hoặc, bạn có thể sử dụng Form_Open() như bình thường và sử dụng các đầu vào ẩn mà được tạo ra cho bạn từ javascript của bạn. Vô hiệu hóa chức năng CSRF là một cách sai lầm.

0

Về cơ bản những gì bạn cần làm là nhận giá trị csrf dự kiến ​​từ cookie (có tên 'ci_csrf_token' theo mặc định), sau đó đăng nó cùng với các dữ liệu khác của bạn.

Bạn sẽ cần phải sửa đổi dòng này:

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

tới:

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

Có thể cần phải cài đặt addon cookie (Tôi không thực sự chắc chắn, tôi sử dụng mootools). Dưới đây là thông tin thêm: http://aymsystems.com/ajax-csrf-protection-codeigniter-20.

12

Bạn có thể thử mã này mà tôi đã sử dụng. Nó hoạt động tuyệt vời:

<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

Như những người khác nói - bạn phải đăng tên mã thông báo CSFR và giá trị của nó bằng tham số yêu cầu AJAX. Đây là một giải pháp đơn giản để tự động thêm nó vào mọi yêu cầu AJAX.

Dưới đây là những gì tôi đặt trên giao diện chính của tôi, do đó, mã này là trên mỗi trang trước khi tải các tập tin javascript khác:

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

Và đây là một phần của một tập tin javascript mà tôi bao gồm trên mỗi trang :

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

giải pháp rất dễ dàng .. làm việc cho tôi :) Cảm ơn @georgiar –

+0

Nhờ thực sự làm việc cho tôi –

0

gợi ý trước đây làm việc tuyệt vời, nhưng thay vì sử dụng một biến mà bạn có thể áp dụng trong tất cả các dữ liệu bài, tôi thấy nó đơn giản để sử dụng ajax-thiết lập để tự động áp dụng thẻ này để mỗi bài:

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

(hoạt động với jquery-1.9.1. Tôi không chắc chắn về các phiên bản jquery khác)

0

Vấn đề duy nhất với một vài câu trả lời ở trên là mã thông báo csrf chỉ hợp lệ cho một yêu cầu, vì vậy nếu bạn thực hiện yêu cầu đăng qua ajax và không làm mới trang bạn sẽ không có mã thông báo csrf hiện tại cho yêu cầu đăng bài ajax tiếp theo của bạn. Đây là giải pháp của tôi:

Trong điều khiển CodeIgniter của bạn:

$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 = dữ liệu để trở về trình duyệt

$ CSRF = new CSRF token để được sử dụng bởi các trình duyệt cho ajax tiếp theo gửi yêu cầu

Rõ ràng bạn có thể xuất kết quả này theo những cách khác nhưng JSON được sử dụng chủ yếu với các cuộc gọi ajax. Cũng bao gồm thẻ này trong mỗi phản ứng bài được sử dụng cho các bài tiếp theo yêu cầu

Sau đó, trong yêu cầu ajax tiếp theo của bạn (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); 
    } 
}); 

Cũng nên nhớ rằng, nơi tôi đã có csrf_token:token thay crf_token với tên mã thông báo của bạn được tìm thấy trong ứng dụng/config/config.php trên dòng có trạng thái $config['csrf_token_name'] = 'csrf_token';

0

Sau khi xem xét trường hợp của tôi, tôi cho rằng tùy chọn tốt nhất là sử dụng mã CSRF nhưng đặt lại. Nếu không, những ý tưởng được trình bày trước đó về việc sử dụng lại mã thông báo cookie sẽ cho phép kẻ tấn công gửi lại dữ liệu hàng trăm lần bằng cách sử dụng cùng một mã thông báo đánh bại đối tượng của điểm đó.

Như vậy tôi đã tạo ra các chức năng sau:

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

Nếu ví dụ một mẫu đăng nhập dựa ajax thất bại - gọi hàm này trong chương trình PHP và sau đó ở phía bên javascript tiếp nhận sự thất bại (giải pháp này sử dụng jquery và một hàm getCookie từ w3schools) sẽ sau đó chỉ cần gọi:

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

Các vấn đề liên quan