【问题标题】:Refresh CSRF Token on AjaxPOST Datatables: CodeIgniter在 AjaxPOST 数据表上刷新 CSRF 令牌:CodeIgniter
【发布时间】:2017-11-27 18:10:42
【问题描述】:

我正在尝试让数据表在我的网站上工作。但是当我点击搜索、下一页、排序时,它不起作用。这是因为 CSRF 令牌没有被重新生成。

这是我的代码:

HTML

<input type="hidden" id="hash" name="csrf_test_name" value="802daa2efaf69edb83b571d7bf7510aa">
        <table id="test-table" class="table table-hover">
            <thead>
                <tr>
                    <th>No</th>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Phone</th>
                    <th>Address</th>
                    <th>City</th>
                    <th>Country</th>
                </tr>
            </thead>
            <tbody>
            </tbody>

            <tfoot>
                <tr>
                    <th>No</th>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Phone</th>
                    <th>Address</th>
                    <th>City</th>
                    <th>Country</th>
                </tr>
            </tfoot>
        </table>

JS

<script type="text/javascript">

var table;

$(document).ready(function() {

//datatables
table = $('#test-table').DataTable({ 

    "processing": true, //Feature control the processing indicator.
    "serverSide": true, //Feature control DataTables' server-side processing mode.
    "order": [], //Initial no order.
    "ajax": {
        "url": "http://oss-dev.forexworld.us/oss/user/ajax_receiving",
        "type": "POST",
        data: {
            'csrf_test_name' : '802daa2efaf69edb83b571d7bf7510aa' 
            },
       dataSrc: function ( json ) {
           if(json.csrf_test_name !== undefined) $('meta[name=csrf_test_name]').attr("content", json.csrf_token);
           return json.data;
       }
    },
    "columnDefs": [
    { 
        "targets": [ 0 ], //first column / numbering column
        "orderable": false, //set not orderable
    },
    ],

});

});

</script>

我可以通过将$config['csrf_regenerate'] = TRUE; 设置为 FALSE 来使我的数据表工作,但我不希望这样。我的猜测是dataSrc 部分不起作用,但我不确定。

您可以看到它的实际效果here

非常感谢任何帮助。谢谢!

【问题讨论】:

  • 一个快速的解决方案是将 ajax 类型更改为 GET。由于 GET 不需要 CSRF 令牌,因此一切正常(尽管需要更改 PHP 代码以使用 $_GET 而不是 $_POST)

标签: javascript php jquery codeigniter datatable


【解决方案1】:

在 AjaxPOST 数据表上刷新 CSRF 令牌:CodeIgniter

上述陈述是不言自明的,并且具有明确的含义:

我们必须在发出任何 AjaxPOST 请求之前刷新我们的 CSRF 令牌

那么,我们将如何在 CodeIgniter 中刷新 CSRF Token & 在 CodeIgniter 中刷新 CSRF 是什么意思。


CSRF 令牌仅在您发出 POST 请求(ajax 帖子或基于普通表单的帖子)时才需要


另外,在发出任何 AjaxPOST 请求之前,您需要拥有新的 CSRF 令牌和哈希值。完成 Ajax 调用后,您必须更新 html 中的令牌和哈希值设置,或在 javascript 代码中另存为变量。


或者,您可以从 CSRF 中排除所需的 url(您可以告诉 CodeIgniter “亲爱的 CodeIgniter 听,当我将使用此 url 时,您不允许检查 CSRF 令牌并且从未要求我附加/发送 CSRF请求中的令牌。明白吗?是大师)使用配置元素 $config['csrf_exclude_uris'] = array('controller/method', '...');


或者,您可以使用配置元素 $config['csrf_expire'] = 300; 设置较长的时间段以使 CSRF 令牌过期。这里定义了 5 分钟以使 CSRF 令牌过期,在过期时间之前(从第一个 POST 时间戳开始),您可以在触发第一个 POST 请求时使用由 CodeIgniter 生成的旧 CSRF 令牌。如果在 5 分钟内第一次 POST 请求后没有触发 POST 请求,CodeIgniter 将使现有的 CSRF 令牌过期,之后您需要再次获取新的 CSRF 令牌。听起来很复杂.. 没问题

假设您重新加载页面并且 CodeIgniter 设置了新的 CSRF 哈希,您可以使用它来发出 AjaxPOST 请求。但是如果不发出任何请求或重新加载页面,则在 5 分钟内,旧的 CSRF 将过期。现在,如果您再次调用 AjaxPOST 请求,您的响应中会出现 500/403 错误。这意味着 CodeIgniter 过期了旧的 CSRF 哈希,因为您在 CSRF 过期时间(5 分钟)期间没有再次发出任何请求,之后当您发送带有 OLD CSRF 令牌的 HTTP POST 请求时,实际上已经消失了......清除:)

那么,在制作 AjaxPOST 时,我们可以做些什么来获取新的 CSRF 令牌..?

  • 好吧,对于 GET 请求,您不需要发送任何 CSRF 令牌。
  • 但是对于 POST 是的!如果你是,你必须在 AjaxPOST 中发送 CSRF 使用 CodeIgniter CSRF 安全 $config['csrf_protection'] = 是的;

背后的逻辑是,在使用 GET 进行任何 AjaxPOST 之前获取新的 CSRF 哈希。将其设置在 DOM 中的某个位置或附加在您的 AjaxSetup 中。

我是 CodeIgniter 的新手.. :( 你有什么例子吗..?

(布尔玛!!为什么你又撞到我的车了……)是的,是的! :)

这里是查看 Html 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    
    <meta charset="utf-8">
    <meta name="<?=$this->security->get_csrf_token_name()?>" content="<?=$this->security->get_csrf_hash()?>"/>

    <title>CodeIgniter CSRF Refresh Demo</title>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

    <script type="text/javascript">

    // Set CodeIgniter base_url in JavaScript var to use within
    var _BASE_URL_ = "<?=base_url()?>";
    var _CSRF_NAME_ = "<?=$this->security->get_csrf_token_name()?>";

    (function($) {
        /**
         * New jQuery function to set/refresh CSRF token in Body & to attach AjaxPOST
         * @param  {[type]} $ [description]
         * @return {[type]}   [description]
         */
         $.fn.CsrfAjaxSet = function(CsrfObject) {
            // getting meta object from body head section by csrf name
            var CsrfMetaObj = $('meta[name="' + _CSRF_NAME_ + '"]'),
            CsrfSecret = {};
            // if CsrfObject not set/pass in function
            if (typeof CsrfObject == 'undefined') {
                // assign meta object in CsrfObject
                CsrfObject = CsrfMetaObj;
                // get meta tag name & value
                CsrfSecret[CsrfObject.attr('name')] = CsrfObject.attr('content');
            }
            // CsrfObject pass in function
            else {
                // get Csrf Token Name from JSON
                var CsrfName = Object.keys(CsrfObject);
                // set csrf token name & hash value in object
                CsrfSecret[CsrfName[0]] = CsrfObject[CsrfName[0]];
            }
            // attach CSRF object for each AjaxPOST automatically
            $.ajaxSetup({
                data: CsrfSecret
            });
        };
        /**
         * New jQuery function to get/refresh CSRF token from CodeIgniter
         * @param  {[type]} $ [description]
         * @return {[type]}   [description]
         */
         $.fn.CsrfAjaxGet = function() {
            return $.get(_BASE_URL_ + 'Csrfdata', function(CsrfJSON) {
                $(document).CsrfAjaxSet(CsrfJSON);
            }, 'JSON');            
        };
    })(jQuery);

    // On DOM ready attach CSRF within AjaxPOST
    $(document).CsrfAjaxSet();

</script>
</head>
<body>
<button class="button">Click Me to Trigger AjaxPOST</button>
    <script type="text/javascript">
        // on DOM ready
        $(document).ready(function(){
            // my button 
            $btn = $('.button');
            // on button click
            $btn.on('click', function(e){
                // stop default event
                e.preventDefault();
                // trigger refresh csrf token
                var CSRF = $(document).CsrfAjaxGet();
                // use callback to put your AjaxPOST & Done!
                CSRF.success(function(){
                    $.ajax({
                        url: _BASE_URL_ + 'Controller/Method',
                        method: 'POST',
                        success: function(data){
                            alert('Success');
                        },
                        error: function(xhr, status, error){
                            alert(error);
                        }
                    });
                });
            });
        });
    </script>
</body>
</html>

这是控制器:

<?php 

(defined('BASEPATH') or exit('No direct script access allowed'));

/**
 * Class Csrfdata to return fresh CSRF hash value
 */
class Csrfdata extends CI_Controller
{

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Return CodeIgniter CSRF name & Hash on request
     * @return [type] [description]
     */
    public function index()
    {
        if ($this->input->get()) {
            $csrf = array();
            $csrf_name = $this->security->get_csrf_token_name();
            $csrf_hash = $this->security->get_csrf_hash();
            $csrf[$csrf_name] = $csrf_hash;
            echo json_encode($csrf);
        }

    }

}

/* End of file Csrfdata.php */
/* Location: ./application/controllers/Csrfdata.php */

希望您喜欢答案和任何建议,非常感谢 cmets...一如既往.. :D

【讨论】:

    【解决方案2】:

    谢谢尼拉杰!您的解决方案对我有用。

    我在 CodeIgniter 中为 AJAX DataTable 使用了以下代码。这是为了在从 DataTable 的 AJAX 调用中获取结果时触发您的 CSRF Refresh 方法。

    $('#table').DataTable({ 
        "ajax": {
            "url": "<?php echo site_url(); ?>list",
            "type": "POST",
            "dataSrc": function ( json ) {
                $(document).CsrfAjaxGet();
                return json.data;
            } 
        }
    });
    

    【讨论】:

    • 哇!很高兴知道它有帮助,非常欢迎您@Belcap :)
    【解决方案3】:

    请将此行添加到您的页面中的脚本标记中。

    $(function($) {
    
        // this script needs to be loaded on every page where an ajax POST
        $.ajaxSetup({
            data: {
                '<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
            }
        });
    
    
      // now write your ajax script 
    
    });
    

    如果它不起作用,请告诉我

    【讨论】:

    • 还是一样的@Shyam Shingadiya :(
    猜你喜欢
    • 2015-03-24
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 2016-07-14
    • 1970-01-01
    • 2016-02-10
    • 2011-07-19
    相关资源
    最近更新 更多