【问题标题】:Disabling CSRF on a specific action CakePHP 3在特定操作上禁用 CSRF CakePHP 3
【发布时间】:2015-06-24 05:16:56
【问题描述】:

所以,我有一个使用DataTables 自动生成的表。我的 CakePHP 中的一个操作会抓取该表的数据,并将其格式化为 JSON 以供数据表使用,这是格式化的 JSON:

<?php
$data = array();
if (!empty($results)) {
    foreach ($results as $result) {
        $data[] = [
          'name' => $result->name,
          'cad' => $this->Number->currency($result->CAD, 'USD'),
          'usd' => $this->Number->currency($result->USD, 'USD'),
          'edit' => '<a href="' .
            $this->Url->build(['controller' => 'Portfolios', 'action' => 'edit', $result->id]) .
    '"><i class="fa fa-pencil"></i></a>',
          'delete' => '<input type="checkbox" class="delete" value="' . $result->id . '">'
        ];
    }
}

echo json_encode(compact('data'));

如您所见,我有一个“删除”选项,它输出一个复选框,其中包含相应元素的 id 值。选中该复选框时,会显示一个删除按钮,该按钮发送此 ajax 请求:

$('a#delete').on('click', function(e) {
    e.preventDefault();
    var checkedValues = [];
    $('input.delete:checked').each(function() {
        checkedValues.push($(this).val());
    });
    $.ajax({
        url: $(this).attr('href'),
        type: 'POST',
        data: checkedValues
    });
})

这个 ajax 帖子转到我的控制器操作 delete()。我遇到的问题是我收到一条错误消息,指出“无效的 Csrf 令牌”。我知道为什么会这样,我正在提交一个启用了 Csrf 保护的表单,它没有添加 Csrf 令牌。

我不知道如何为这种情况手动创建 Csrf 令牌(在页面加载后生成输入值)。我也不知道如何禁用 Csrf 保护。我读了this,但代码放在 beforeFilter 函数中,据我了解,这意味着它在每个动作上运行,而不仅仅是这个,这不是我想要的。另外,老实说,我更喜欢不禁用安全功能的解决方案。

是否有为此特定操作禁用 Csrf,或者有更好的方法来做到这一点?

【问题讨论】:

    标签: cakephp cakephp-3.0


    【解决方案1】:

    在 Application.php 中这对我有用....

        $csrf = new CsrfProtectionMiddleware();
        
        // Token check will be skipped when callback returns `true`.
        $csrf->whitelistCallback(function ($request) {
        // Skip token check for API URLs.
          if ($request->getParam('controller') === 'Api') {
              return true;
          } 
    
        });
    

    【讨论】:

      【解决方案2】:

      以上答案在 Cakephp 3.6 或更高版本中不起作用。

      Cakephp 在 src/Application.php 中添加 CsrfProtectionMiddleware 对象。 如果您必须删除特定控制器或操作的 CSRF 保护,则可以使用以下解决方法:

      public function middleware($middlewareQueue)
      {
          $middlewareQueue = $middlewareQueue
              // Catch any exceptions in the lower layers,
              // and make an error page/response
              ->add(ErrorHandlerMiddleware::class)
      
              // Handle plugin/theme assets like CakePHP normally does.
              ->add(AssetMiddleware::class)
      
              // Add routing middleware.
              // Routes collection cache enabled by default, to disable route caching
              // pass null as cacheConfig, example: `new RoutingMiddleware($this)`
              // you might want to disable this cache in case your routing is extremely simple
              ->add(new RoutingMiddleware($this, '_cake_routes_'));
              /*
              // Add csrf middleware.
              $middlewareQueue->add(new CsrfProtectionMiddleware([
                  'httpOnly' => true
              ]));
              */
          //CSRF has been removed for AbcQutes controller
          if(strpos($_SERVER['REQUEST_URI'], 'abc-quotes')===false){
              $middlewareQueue->add(new CsrfProtectionMiddleware([
                  'httpOnly' => true
              ]));
          }
          return $middlewareQueue;
      }
      

      【讨论】:

        【解决方案3】:

        在此处阅读有关 CSRF 组件的所有信息

        http://book.cakephp.org/3.0/en/controllers/components/csrf.html

        您可以在此处禁用特定操作:

        http://book.cakephp.org/3.0/en/controllers/components/csrf.html#disabling-the-csrf-component-for-specific-actions

         public function beforeFilter(Event $event) {
             if (in_array($this->request->action, ['actions_you want to disable'])) {
                 $this->eventManager()->off($this->Csrf);
             }
         }
        

        【讨论】:

        • 我试过了,但它不起作用。这会禁用操作的安全性,而不是 Csrf,它们是两个独立的组件。
        • 我的错误,我读你的问题太快了 :) 我编辑了我的答案
        • 正如我所说,并在我的问题中链接到,我已经读过了。但据我了解,这会在 Controller 中的每个操作中禁用 Csrf,因为它是在 BeforeFilter 方法中运行的。
        • 是的,但我认为您可以针对单个操作,我再次更改了答案:)
        • 这在 cakephp 3.7 中不起作用我想为用户控制器禁用
        【解决方案4】:

        所以我需要对 cakephp 3.7 进行修复,并且使用 $_SERVER['REQUEST_URI'] 真的不是这里的方法。因此,在阅读了一些文档后,您应该这样做。

        在 src/Application.php 添加这个函数

        public function routes($routes)
        {
            $options = ['httpOnly' => true];
            $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware($options));
            parent::routes($routes);
        }
        

        注释掉现有的 CsrfProtectionMiddleware

        public function middleware($middlewareQueue)
        { 
          ...
          //            $middlewareQueue->add(new CsrfProtectionMiddleware([
          //                'httpOnly' => true
          //            ]));
        }
        

        打开你的 config/routes.php 添加 $routes->applyMiddleware('csrf');你想要的地方

        Router::prefix('api', function ($routes)
        {
          $routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
          $routes->fallbacks(DashedRoute::class);
        });
        
        Router::scope('/', function (RouteBuilder $routes)
        {
          $routes->applyMiddleware('csrf');
          $routes->connect('/', ['controller' => 'Pages', 'action' => 'dashboard']);
          $routes->fallbacks(DashedRoute::class);
        });
        

        请注意,我的 api 用户现在没有 csrf 保护,而基本调用确实有它。 如果您有更多前缀,请不要忘记在此处添加该功能。

        【讨论】:

          猜你喜欢
          • 2019-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-26
          • 2015-10-22
          • 1970-01-01
          相关资源
          最近更新 更多