繁体   English   中英

Codeigniter CSRF仅对一次ajax请求有效

[英]Codeigniter CSRF valid for only one time ajax request

我想在 jQuery 的更改事件上在服务器上上传图像,但使用 codeigniter csrf 我只能上传图像一次。 如何使用ajax为多个请求上传图像。设置时请记住

config['csrf_protection'] = FALSE;

然后我可以发送多个请求 jQuery onchange 事件,但是当 csrf_protection 为 false 时,我认为 csrf 没有优势。 所以问题是如何在启用 csrf_protection 的情况下使用 ajax 发送多个请求。 我的 jquery 代码如下

$("#avatar").change(function(){
    var link = $("#avatar").val();     
    $.ajax({
        url : "<?php echo base_url('main/test'); ?>",
        type: 'post',
        data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>',"id":"hello","link":link},            
        success : function(data)
        {   
            alert(data);
        }  
    });
});

我认为您应该尝试在每个请求中重新创建您的 csrf 令牌

试试这个代码示例...

对于 js 函数

var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
    csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
("#avatar").change(function(){
    var link = $("#avatar").val();

    var dataJson = { [csrfName]: csrfHash, id: "hello", link: link };

    $.ajax({
        url : "<?php echo base_url('main/test'); ?>",
        type: 'post',
        data: dataJson,            
        success : function(data)
        {   
            csrfName = data.csrfName;
            csrfHash = data.csrfHash;
            alert(data.message);
        }  
    });
});

和控制器

public function test() { 
    $config['upload_path'] = './uploads/'; 
    $config['allowed_types'] = 'gif|jpg|png'; 
    $config['max_size'] = 500; 
    $config['max_width'] = 260; 
    $config['max_height'] = 260; 

    $reponse = array(
                'csrfName' => $this->security->get_csrf_token_name(),
                'csrfHash' => $this->security->get_csrf_hash()
                )

    $this->load->library('upload', $config); 
    if (!$this->upload->do_upload('link')) { 
        $reponse['message'] = "error"; 
    } 
    else { 
        $data = array('upload_data' => $this->upload->data()); 
        $image_name = $data['upload_data']['file_name']; 
        $reponse['message'] = $image_name; 
    } 

    echo json_encode($reponse);
}

让我知道并祝你好运

注意:当有人要求您为问题发布更多数据时,请勿将其作为评论或答案发布,最好编辑问题本身并添加内容

你可以在 config.php 中设置

$config['csrf_regenerate'] = FALSE;

因此 csrf 保护在所有会话时间内都是有效的,它将解决您的问题。 如果你设置$config['csrf_regenerate'] = true; 然后 CI 为每个请求生成新的 csrf 令牌,因此您的旧 csrf 令牌与新生成的 csrf 令牌不匹配

您需要做的就是在 AJAX 响应中重新加载 CSRF 令牌。 就是这么简单!。

$config['csrf_regenerate'] = TRUE;

保持自动生成为真它会更安全。 在类似的情况下,当 csrf 在第一个请求中过期时。 我已经实施的

$(document).ajaxComplete(function (event, xhr, settings) {
 let response = xhr.responseText,
 let obj = JSON.parse(response),
 let csrfData = obj.csrf;
 document.querySelector('input[name="' + csrfData.name + '"]').value = csrfData.hash; 
}); //Also here you can update any other non input element    

在每个 ajax 响应中,我们都传递 csrf 数据,其中最新的 csrf 数据将替换为当前的

请求响应示例

{ 
csrf : {
  name : 'csrf_name',
  hash : 'qw76sd7s6f78sdfs8dfs9df8cx9'
 }
}

我在每个 ajax 请求中更新 csrf 令牌。 如果您正在使用多选项卡环境,也不要选择此方法

每次发出请求时, csrf_token都会被CI更新。 这就是CSRF只工作一次的原因。 所以每次我们发出请求时,我们也需要更新 csrf_token。 我通过这样做解决了这个问题。

电脑板获得更新的CSRF使用此代码

public function update_csrf()
{
  $data['csrf_hash'] = $this->security->get_csrf_hash();
  echo json_encode($data);
}

AJAX替换您的csrf name="csrf_token_name"的旧值

var jqXHR = $.ajax({
            url: $(this).attr('action'),
            type: 'POST',
            data: $(this).serialize(),
            dataType: 'json',
        })
        jqXHR.done(function(response) {
            $('input[name=csrf_token_name]').val(response.csrf_hash); //update the csrf to the form 
        })
        jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR);
            console.log(textStatus);
            console.log(errorThrown);
        });

重要!:使用dataType: 'json'

所以现在每次你有一个成功的请求时, csrf_token也会更新,你现在没有403 (Forbidden) error

将此添加到每个页面加载的 js 文件中(我将其放在 jquery.js 的末尾)

    $.ajaxSetup({
        beforeSend:function(jqXHR, Obj){
            var value = "; " + document.cookie;
            var parts = value.split("; csrf_cookie_name=");
            if(parts.length == 2)   
            Obj.data += '&csrf_token='+parts.pop().split(";").shift();
        }
    });

(请注意,在每个 ajax 请求中,您不能发送空数据)

在 config.php 中定义的顶部的“csrf_cookie_name”

$config['csrf_cookie_name'] = 'csrf_cookie_name';

请尝试像我的代码。 它正在运行我的应用程序

你的视图文件

$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();

<input type="text" id="search-text" name="parent_name" placeholder="Search" value=""  >
<input type="hidden" id="csrf" name="<?php echo $token_name; ?>" value="<?php echo $token_hash; ?>" />

设置 jquery post 方法后,如下所示

// Get Keyup 
jQuery( "#search-text").keyup(function() {
    // Get Data 
    var val       = jQuery("#search-text").val();
    var hashValue = jQuery('#csrf').val();

    // Get jquery post for ajax task
    jQuery.post( 
        '<?php echo $base_controler; ?>',
        {val:val,'<?php echo $this->security->get_csrf_token_name(); ?>':hashValue}, 
        function(data)
        { 
            // Get return data to decode
            var obj = jQuery.parseJSON(data);
            // Get csrf new hash value
            var new_hash = obj.csrfHash;
            // Set csrf new hash value update
            jQuery('#csrf').val(new_hash);

        }
    );        

});

请设置您的控制器如下

$reponse = array(
        'csrfName' => $this->security->get_csrf_token_name(),
        'csrfHash' => $this->security->get_csrf_hash()
        );
echo json_encode($reponse);

最重要的是,代码在每个请求中重新创建您的 csrf 令牌。

也许你可以尝试使用 jquery cookie

首先你需要添加这个

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>

然后将您的代码更改为此

$("#avatar").change(function(){
var link = $("#avatar").val();     
$.ajax({
    url : "<?php echo base_url('main/test'); ?>",
    type: 'post',
    data: {csrf_test_name: $.cookie('csrf_cookie_name'),"id":"hello","link":link},
    dataType : "JSON",
    success : function(data)
    {   
        alert(data);
    }  
});

最后,您可以尝试将 csrf_protection 设置为 true

[csrf_protection] = TRUE;

编辑配置:

$config['csrf_exclude_uris'] = ['controller/method'];

Array 可以包含您希望禁用 csrf 保护的所有列入白名单的控制器/方法。

该数组还可以处理正则表达式,例如:

$config['csrf_exclude_uris'] = array(
                                        'api/record/[0-9]+',
                                        'api/title/[a-z]+'
                                );

有关更多信息,请访问Codeigniter 文档 - 安全类

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM