php Codeigniter CSRF仅对一次ajax请求有效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38502548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:36:15  来源:igfitidea点击:

Codeigniter CSRF valid for only one time ajax request

phpjqueryajaxcodeignitercsrf-protection

提问by romio

I want to upload image on the server on change event of jQuery but using codeigniter csrf I am able to upload image only one time. How can I upload images using ajax for multiple requests.Please keep in mind when I set this

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

config['csrf_protection'] = FALSE;

then I am able to send multiple request jQuery onchange event but when csrf_protection is going to be false then I think there is no advantage of csrf. so the question is how can I send multiple requests using ajax while csrf_protection is enable. My jquery code is following

然后我可以发送多个请求 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);
        }  
    });
});

回答by Edu

In my opinion you should try to recreate your csrf token each request

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

Try this code example...

试试这个代码示例...

For the js funcion

对于 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);
        }  
    });
});

and for the controller

和控制器

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

Let me know and good luck

让我知道并祝你好运

Note:When someone ask you for posting more data to the question, don't post it as a comment or answer, it's better to edit the question itself and adding the stuff

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

回答by Brian85

You can set this in config.php

你可以在 config.php 中设置

$config['csrf_regenerate'] = FALSE;

so the csrf protection is valid during all the session time it will solve your problem. If you set $config['csrf_regenerate'] = true;then CI generate new csrf token every request so your old csrf token not match with new generated csrf token

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

回答by Brian85

All you need to do is reload the CSRF token in your AJAX response. It is that simple!.

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

回答by Vishnu Bhadoriya

$config['csrf_regenerate'] = TRUE;

$config['csrf_regenerate'] = TRUE;

keep auto generate to true it will be more safer. In similar case when csrf is expired in first request. What i have implemented

保持自动生成为真它会更安全。在类似的情况下,当 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    

In every ajax response we are passing csrf data in which latest csrf data will be replaced with current one

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

Sample response from request

请求响应示例

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

I update csrf token in every ajax request. Also don't choose this method if you are working with multi tab environment

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

回答by curiosity

Each time you make a request, the csrf_tokenis being updated by CI. That's why the CSRFonly work once. So everytime we make a request we need to update the csrf_token too. I solve this problem by doing this.

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

Conroller: get the updated csrf using this code.

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

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

AJAX: replace the old value of yourcsrfname="csrf_token_name"

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

Important!: use dataType: 'json'

重要!:使用dataType: 'json'

So now each time you have a successful request, the csrf_tokenis updated too and you are now free from 403 (Forbidden) error.

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

回答by Kevin TP

Maybe you can try using jquery cookie

也许你可以尝试使用 jquery cookie

First you need to add this

首先你需要添加这个

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

then change your code to this

然后将您的代码更改为此

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

Finally you can try to set your csrf_protection to true

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

[csrf_protection] = TRUE;

回答by mohammad aghandeh

add this at a js file which is loaded every page (I put this at the end of jquery.js )

将此添加到每个页面加载的 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();
        }
    });

(notice that in every ajax request you can not have empty data to send)

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

"csrf_cookie_name" at top defined in config.php

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

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

回答by Md Suzon Mia

Please try like my code. its working my application

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

your view file

你的视图文件

$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; ?>" />

after set jquery post method like below

设置 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);

        }
    );        

});

please set your controller like below

请设置您的控制器如下

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

above all code recreate your csrf token each request.

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

回答by Mike

Edit the config:

编辑配置:

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

Array can include all whitelisted controllers/methods you want the csrf protection to be disabled for.

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

The array can also handle regular expressions such as:

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

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

For more information visit Codeigniter Documentation - Security Class

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