【问题标题】:jquery ajax call forbidden by codeigniter 3 csrfjquery ajax调用被codeigniter 3 csrf禁止
【发布时间】:2017-08-05 16:06:02
【问题描述】:

windows 10,codeigniter 3,jquery 3

我正在测试 ajax 函数,我正在使用 $.post 函数将数据加载到 div 中,并发送到读取文件并发回内容的控制器方法(我知道还有其他方法可以做到这一点,但是这是一个测验)。 ajax 调用是这样的

    var btn = 'a[href="click-help"]'
    $(btn).click(function(){

            $.post(
                base_url+'site/cal_help', 
                function(data){
                    $('.cal-help').html(data);
                });
        }
        return false;
    });

可以看到点击按钮不是表单而是链接。当我将 csrf 设置为 false 时,这可以正常工作,但如果启用了 csrf,控制台会将调用显示为禁止。经过网上研究,我尝试按如下方式传递数据:

    {
                    '<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
    }, 

但这无济于事。如何在不将 csrf 设置为 false 的情况下修复它,如果我希望它用于站点中的其他元素,我宁愿不这样做?

【问题讨论】:

    标签: jquery ajax codeigniter


    【解决方案1】:

    我仍在努力解决这个问题,我发现了一些更有趣的事情:

    虽然您可以像这样使用 Codeigniter Security 类:

    <?php echo $this->security->get_csrf_token_name(); ?>
    <?php echo $this->security->get_csrf_hash(); ?>
    

    在视图中并且这些功能有效,您还应该能够在脚本文件中使用它们,例如

    var hash = '<?php echo $this->security->get_csrf_hash();?>';
    console.log(hash);
    

    这似乎在视图中的脚本标签中起作用,但如果在单独的 script.js 文件中,控制台只会显示打印出来的代码。为什么会发生这种情况?

    但是我研究了 js 字符串方法,发现以下方法可以检索哈希:

    //get all cookies
    var x = document.cookie;
    //search for the csrf cookie name
    var posname = x.search('csrf_cookie_name');
    //slice out hash itself which is always 32 characters long and these numbers work
    var hash = x.slice(posname+17,posname+49);
    console.log(hash);
    

    已经建立了一个等于散列的变量,您可以将以下数据添加到您的 ajax 调用中:

    {
       'csrf_test_name' : hash
    },
    

    我将所有内容放在“点击”函数中,以便它找到最新版本的 cookie。所以我最终得到了这样的结果:

    var btn = '.btn-cal-help a';
    $(btn).click(function(){
        var x = document.cookie;
        var posname = x.search('csrf_cookie_name');
        var hash = x.slice(posname+17,posname+49);
        //console.log(hash);    
            $.post(
                base_url + 'site/cal_help', 
                {
                    'csrf_test_name' : hash
                }, 
                function(data){
                    $('.cal-help').html(data);
                });
        }
        return false;
    });
    

    现在这对我有用(在我的本地服务器 - wamp 上),即使我也将 'csrf_regenerate' 设置为 TRUE。

    【讨论】:

    • 我的回答将帮助您了解它的工作原理,并根据您的需要进行调整
    【解决方案2】:

    在所有 ajax 请求中启用 CSRF 保护的项目中,我确实遇到了类似的问题。然后我发现这是因为 csrf 令牌在每个请求上重新生成,这将导致禁止错误,因为令牌不匹配。所以解决方案是在每个请求上关闭 CSRF 令牌生成。您可以通过在 config.php 文件中设置此选项来实现。

    $config['csrf_regenerate'] = FALSE;
    

    请注意,当我检查 laravel 的 CSRF 令牌时,它不会在所有请求中发生变化。因此将 csrf 重新生成选项更改为 false 不会导致任何重大安全问题。如果上述方法不适合您,请在下方评论。

    【讨论】:

      【解决方案3】:

      就这么简单。获取每个新请求的令牌和哈希并将其附加到您的帖子数据中

      在你的模型/控制器中放置这样的东西

      $reponse = array(
                      'csrfName' => $this->security->get_csrf_token_name(),
                      'csrfHash' => $this->security->get_csrf_hash()
                  );
      // Your logic
      
       return $this->output
                                  ->set_content_type('application/json')
                                  ->set_status_header(200)
                                  ->set_output(json_encode(array("regen" => $reponse, "response" => array("status" => $status, "message" => $message))));
      

      在javascript部分

          var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
                      csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
      
      $.ajax({
                      url: __URL__,
                      type: "POST",
                      data: $form.serialize() + "&" + csrfName + "=" + csrfHash,
                      mimeType: "multipart/form-data",
                      contentType: false,
                      dataType: 'json',
                      cache: false,
                      processData: false,
      
                      success: function (data) {
      
                          csrfName = data.regen.csrfName;
                          csrfHash = data.regen.csrfHash;
      
                          if (data.response.status) // if STATUS = TRUE
                          {
                              if (data.response.message === "__WHATEVER__") {
                                  // and message === "__WHATEVER__"
      
                              }
                          }
                      }
                  });
      

      【讨论】:

      • 对不起,我不关注这个。您已使用 Security 类函数在控制器中获取 csrf 名称和哈希,然后在 javascript 中再次完全独立地找到它们。为什么两者都有?对不起,如果昏暗。此外,在我单独的“script.js”文件中,使用 Security 类函数的 javascript 代码对我不起作用。如果我将所有 js 放在视图中的脚本标记之间,它确实有效。你能解释一下吗?
      • 好吧,我把它放在模型中,是的,这个在外部 js 文件中不起作用。您需要为此使用 cookie 方法。 Js 代码获取请求的令牌/哈希,响应为下一个请求分配新的,但如前所述,除非您的视图中没有 js 代码,否则它不适合您/一个选项可能是禁用特定的 csrf你的 config.php 页面 - $config['csrf_exclude_uris']
      【解决方案4】:

      $config['csrf_protection'] = TRUE; 设置为FALSE 并不是解决该问题的好方法。 AJAX 请求期间发生的情况是,当请求发送到您的控制器时,它将在提交期间验证有效令牌。因此,您需要传递令牌名称和哈希令牌,以便将其读取为有效。

      这里是……

      $.ajax({
             url: url,
             type: "post",
             data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>'},
                  success:function() {
                                    //do stuff here...
                                  }
       });
      

      【讨论】:

        猜你喜欢
        • 2017-01-25
        • 1970-01-01
        • 2017-05-15
        • 2013-08-24
        • 2011-11-13
        • 1970-01-01
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多