Javascript Codeigniter ajax CSRF问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7348383/
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-24 01:55:19  来源:igfitidea点击:

Codeigniter ajax CSRF problem

javascriptajaxcodeignitertoken

提问by Dexty

I've made a simple autoload function that loads content when you scroll down on a website. However, there seems to be a few problems when i enable CSRF protection in Codeigniter.

我制作了一个简单的自动加载功能,可以在您向下滚动网站时加载内容。但是,当我在 Codeigniter 中启用 CSRF 保护时,似乎存在一些问题。

I'm not using a form, so i don't know how i can send the token from A to B when i'm doing my post request as you scroll.

我没有使用表单,所以我不知道如何在滚动时执行发布请求时将令牌从 A 发送到 B。

My JavaScript

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

Since Codeigniter expects a TOKEN on all POST request i can't get this to work when CSRF i enabled. Any suggestions?

由于 Codeigniter 期望在所有 POST 请求上都有一个令牌,因此当我启用 CSRF 时,我无法让它工作。有什么建议?

Error when CSRF is Enabled

启用 CSRF 时出错

Failed to load resource: the server responded with a status of 500 (Internal Server Error)

加载资源失败:服务器响应状态为 500(内部服务器错误)

If i turn CSRF off, everything works great...

如果我关闭 CSRF,一切正常...

回答by imsyedahmed

You might like to try this code I've used. It works great:

你可能想试试我用过的这段代码。它工作得很好:

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

回答by georgiar

As others say - you have to post the CSFR token name and its value with the AJAX request parameters. Here is a simple solution to append it automatically to every AJAX request.

正如其他人所说 - 您必须使用 AJAX 请求参数发布 CSFR 令牌名称及其值。这是一个简单的解决方案,可以将它自动附加到每个 AJAX 请求。

Here is what I put on my main view, so this code is on every page before loading the other javascript files:

这是我放在主视图中的内容,因此在加载其他 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>

And here is a part of a javascript file that I include on every page:

这是我包含在每个页面上的 javascript 文件的一部分:

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

回答by Tobias

If you want, you can echo both the token name and the hash somewhere appropriate. Something like this.

如果需要,您可以在适当的地方同时回显令牌名称和哈希值。像这样的东西。

 echo $this->security->get_csrf_token_name()

and

 echo $this->security->get_csrf_hash()

Or, you could use form_open() as usual and use the hidden input that is generated for you from your javascript. Disabling the CSRF-functionality is the wrong way to go.

或者,您可以像往常一样使用 form_open() 并使用从您的 javascript 为您生成的隐藏输入。禁用 CSRF 功能是错误的方法。

回答by Antony

Having reviewed my situation I believe the best option is to use CSRF but resetthe token on each attempt. Otherwise the ideas expressed earlier about re-using the cookie token would allow an attacker to resubmit data hundreds of times using the same token which defeats the object of the point.

回顾我的情况后,我认为最好的选择是使用 CSRF,但在每次尝试时重置令牌。否则,之前表达的关于重新使用 cookie 令牌的想法将允许攻击者使用相同的令牌重新提交数据数百次,这会破坏该点的对象。

As such I have created the following function:

因此,我创建了以下函数:

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

If for example an ajax based login form fails - call this function in your PHP and then on the javascript side that receives the failure (this solution uses Jquery and a getCookie function from w3schools) would then simply call:

例如,如果基于 ajax 的登录表单失败 - 在您的 PHP 中调用此函数,然后在接收失败的 javascript 端(此解决方案使用 Jquery 和 w3schools 的 getCookie 函数)将简单地调用:

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

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

回答by Osan

Basically what you need to do is get the expected csrf value from the cookie (named 'ci_csrf_token' by default), then post it along with your other data.

基本上,您需要做的是从 cookie(默认名为“ci_csrf_token”)中获取预期的 csrf 值,然后将其与其他数据一起发布。

You would need to modify this line:

您需要修改此行:

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

to:

到:

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

Might need to install the cookie addon (I'm not really sure; I use mootools). Here is more information: http://aymsystems.com/ajax-csrf-protection-codeigniter-20.

可能需要安装 cookie 插件(我不太确定;我使用的是 mootools)。以下是更多信息:http: //aymsystems.com/ajax-csrf-protection-codeigniter-20

回答by Kevin Driessen

Previous suggestions work great, but rather than using a variable that you can apply in every data-post, I find it simpler to use the ajax-setting to automatically apply this token to every post:

以前的建议效果很好,但我发现使用 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(); ?>';
    }); 

(works with jquery-1.9.1. I'm not sure about other jquery-versions)

(适用于 jquery-1.9.1。我不确定其他 jquery 版本)

回答by OGZStudio

The only problem with a few of the above answers is that a csrf token is only valid for one request, so if you make a post request via ajax and do not refresh the page you will not have the current csrf token for your next ajax post request. This is my solution:

上述几个答案的唯一问题是 csrf 令牌仅对一个请求有效,因此,如果您通过 ajax 发出发布请求并且不刷新页面,则下一个 ajax 发布将没有当前的 csrf 令牌要求。这是我的解决方案:

In your CodeIgniter Controller:

在您的 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 = the data to return to the browser

$data = 返回浏览器的数据

$csrf = new csrf token to be used by the browser for next ajax post request

$csrf = 浏览器用于下一个 ajax post 请求的新 csrf 令牌

Obviously you can output this in other ways but JSON is used mostly with ajax calls. Also include this token in every post response to be used for the next post request

显然,您可以通过其他方式输出它,但 JSON 主要用于 ajax 调用。还要在每个帖子响应中包含此令牌以用于下一个帖子请求

Then in your next ajax request (javascript):

然后在您的下一个 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 );
    }
});

Also remember that where I've got csrf_token:tokenreplace crf_tokenwith the name of your token found in application/config/config.php on line that states $config['csrf_token_name'] = 'csrf_token';

还请记住,我在哪里用您在 application/config/config.php 中找到的令牌名称csrf_token:token替换crf_token了该名称,说明$config['csrf_token_name'] = 'csrf_token';