Cakephp 3.5.6禁用控制器CSRF中间件

p8h8hvxi  于 2022-11-12  发布在  PHP
关注(0)|答案(4)|浏览(140)

我试图禁用单个控制器(API)的CSRF检查,但我无法找到如何实现这一点。
3.5.0之前的CSRF组件能够根据特定请求使用以下功能禁用:

$this->eventManager()->off($this->Csrf);
bqjvbblv

bqjvbblv1#

有两种方法。

将中间件应用于特定的路由范围(甚至路由)

根据您创建的路由,您可以将中间件仅应用于特定的作用域,例如:

// config/routes.php

use Cake\Http\Middleware\CsrfProtectionMiddleware;

Router::scope('/', function ($routes) {
    $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware([
        'httpOnly' => true
    ]));

    $routes->scope('/api', function ($routes) {
        // ...
    });

    $routes->scope('/blog', function ($routes) {
        $routes->applyMiddleware('csrf');
        // ...
    });

    $routes->scope('/cms', function ($routes) {
        $routes->applyMiddleware('csrf');
        // ...
    });
});

这将仅将CSRF中间件应用于在blogcms作用域中连接的路由。
还可以将范围进一步缩小到路由级别,并在特定路由上应用中间件:

$routes
    ->connect('/blog/:action', ['controller' => 'Blogs'])
    ->setMiddleware(['csrf']);

这会将CSRF中间件仅应用于/blog/*路由。

有条件地“手动”应用中间件

另一种方法是在合适的时候手动应用中间件。从CakePHP 3.8开始,中间件有一个名为whitelistCallback的白名单方法,在其中你可以检查请求对象,并返回一个布尔值来定义是否应用检查:

// src/Application.php

// ...
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Psr\Http\Message\ServerRequestInterface;

class Application extends BaseApplication
{
    // ...

    public function middleware($middleware)
    {
        $csrf = new CsrfProtectionMiddleware([
            'httpOnly' => true
        ]);
        $csrf->whitelistCallback(function (ServerRequestInterface $request) {
            $params = $request->getAttribute('params');
            return $params['controller'] !== 'Api';
        });

        $middleware
            // ...
            ->add(new RoutingMiddleware())

            ->add($csrf);

        return $middleware;
    }
}

在早期的CakePHP版本中,您必须创建一个自定义的中间件处理程序,以便访问当前的请求对象,从中提取controller参数,然后您必须在处理程序中 * 调用 * CSRF中间件,大致如下:

// src/Application.php

// ...
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Application extends BaseApplication
{
    // ...

    public function middleware($middleware)
    {
        $middleware
            // ...
            ->add(new RoutingMiddleware())

            ->add(function (
                ServerRequestInterface $request,
                ResponseInterface $response,
                callable $next
            ) {
                $params = $request->getAttribute('params');
                if ($params['controller'] !== 'Api') {
                    $csrf = new CsrfProtectionMiddleware([
                        'httpOnly' => true
                    ]);

                    // This will invoke the CSRF middleware's `__invoke()` handler,
                    // just like it would when being registered via `add()`.
                    return $csrf($request, $response, $next);
                }

                return $next($request, $response);
            });

        return $middleware;
    }
}

请注意,在这两种情况下,您必须将中间件放在路由中间件 * 之后 *,因为这是设置控制器信息的位置。
如果适用,您还可以针对请求URL而不是路由参数进行测试,例如:

if (mb_strpos($request->getUri()->getPath(), '/api/') === false) {
    // apply CSRF checks
}

这样做的话,中间件就不会被限制在路由中间件 * 之后 *,理论上你可以把它放在你想要的任何位置。

另请参阅

*操作手册〉中间件〉跨站点请求伪造(CSRF)中间件
*操作手册〉路由〉连接作用域中间件
*操作手册〉中间件〉创建中间件

6jygbczu

6jygbczu2#

我认为在Cake 3.6中,您应该从中间件中删除CsrfProtectionMiddleware:
队列:src/应用程序. php

public function middleware($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(new AssetMiddleware([
            'cacheTime' => Configure::read('Asset.cacheTime')
        ]))

        // 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.
        //            ->add(new CsrfProtectionMiddleware([
        //                'httpOnly' => true
        //            ]));

        return $middlewareQueue;
     }
bakd9h0s

bakd9h0s3#

在Cakephp 3.8中,我将所有方法实现注解到class\vendor\cakephp\cakephp\src\Http\Middleware\CsrfProtectionMiddleware.php中,因此禁用了Csrf中间件:-)

y3bcpkx1

y3bcpkx14#

3.8、3.9的最新解决方案

首先从route.php中删除中间件。

Router::scope('/', function (RouteBuilder $routes) {
    // Register scoped middleware for in scopes.
    $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware([
        'httpOnly' => true
    ]));

    /**
     * Apply a middleware to the current route scope.
     * Requires middleware to be registered via `Application::routes()` with `registerMiddleware()`
     */
    $routes->applyMiddleware('csrf');

    //...
}

注解注册中间件应用中间件('csrf')

Router::scope('/', function (RouteBuilder $routes) {
    //    // Register scoped middleware for in scopes.
    //    $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware([
    //        'httpOnly' => true
    //    ]));
    //
    //    /**
    //     * Apply a middleware to the current route scope.
    //     * Requires middleware to be registered via `Application::routes()` with `registerMiddleware()`
    //     */
    //    $routes->applyMiddleware('csrf');
//...
}

现在,编辑**/Application.php中的中间件()**函数:

/**
     * Setup the middleware queue your application will use.
     *
     * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup.
     * @return \Cake\Http\MiddlewareQueue The updated middleware queue.
     */
    public function middleware($middlewareQueue)
    {
       // loading csrf Middleware ---- Add this code Block
        $csrf = new CsrfProtectionMiddleware([
            'httpOnly' => true
        ]);
        $csrf->whitelistCallback(function (ServerRequest $request) {
            // skip controllers
            $skipedControllers = ['MyControllerToSkip', 'MyControllerToSkip2']; // EDIT THIS 
            if(in_array($request->getParam('controller'),$skipedControllers)) {
                return true;
            }
            // skip debugkit
            if($request->getParam('plugin') == 'DebugKit') {
                return true;
            }
            return $request;
        });
        // end codeblock to add, you have to add a other code line below ->add(new RoutingMiddleware($this)) -------

        $middlewareQueue
            // Catch any exceptions in the lower layers,
            // and make an error page/response
            ->add(new ErrorHandlerMiddleware(null, Configure::read('Error')))

            // Handle plugin/theme assets like CakePHP normally does.
            ->add(new AssetMiddleware([
                'cacheTime' => Configure::read('Asset.cacheTime')
            ]))

            // Add routing middleware.
            // If you have a large number of routes connected, turning on routes
            // caching in production could improve performance. For that when
            // creating the middleware instance specify the cache config name by
            // using it's second constructor argument:
            // `new RoutingMiddleware($this, '_cake_routes_')`
            ->add(new RoutingMiddleware($this))
            ->add($csrf);   // <---- Don't forget to add this !  

        return $middlewareQueue;
    }

不要忘记最后的**-〉add($csrf);之后-〉添加(新的路由中间件($this))**。

相关问题