Disabling CSRF on a specific action CakePHP 3

為{幸葍}努か 提交于 2019-12-19 04:09:53

问题


So, I have a table that is auto-generated using DataTables. An action in my CakePHP grabs the data for that table, and formats it into JSON for datatables to use, this is the formatted 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'));

As you can see, I have a 'delete' option in there that outputs a checkbox with the value of the id of the corresponding element. When that checkbox is checked, a delete button is showing which sends this ajax request:

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

This ajax post goes to my controller action delete(). The problem I'm having is that I'm getting an error that states "Invalid Csrf Token". I know why this is happening, I'm submitting a form with Csrf protection on, that has no Csrf token added to it.

I can't figure out how to manually create a Csrf token for this situation (where the input values are generated after the page has loaded). Nor can I figure out how to disable Csrf protection. I read this, but the code is placed in the beforeFilter function, and as far as I understand it, that means it's run on every action, not just this one, and that's not what I want. Plus, to be completely honest, I would prefer a solution where I don't deactivate security functions.

Is there anyway to disable Csrf for this specific action, or is there a better way to do this?


回答1:


read all about the CSRF component here

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

you can disable for a specific action here:

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



回答2:


So i needed a fix for cakephp 3.7 and using $_SERVER['REQUEST_URI'] is realllly not the way to go here. So here is how you are supposed to do it after reading through some documentation.

In src/Application.php add this function

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

Comment out the existing CsrfProtectionMiddleware

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

Open your config/routes.php add $routes->applyMiddleware('csrf'); where you do want it

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

Note that my api user now has no csrf protection while the basic calls do have it. If you have more prefixes don't forgot to add the function there aswell.




回答3:


Above answer does not work in Cakephp 3.6 or later.

Cakephp add object of CsrfProtectionMiddleware in src/Application.php. If you have to remove CSRF protection for specific controller or action then you can use following work around:

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


来源:https://stackoverflow.com/questions/31018156/disabling-csrf-on-a-specific-action-cakephp-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!