如何使用 Slim 4 和 slim/csrf 实现 CSRF 保护?
How do I implement CSRF protection with Slim 4 and slim/csrf?
Slim 4 已经在这里,我正在尝试迁移到 Slim 4。一切都很好,但是 CSRF returns 在我尝试实现它时出现错误。我尝试了最简单的设置,但出现此错误:
Message: Argument 2 passed to Slim\Csrf\Guard::__invoke() must be an instance of Psr\Http\Message\ResponseInterface, instance of Slim\Routing\RouteRunner given, called in /Volumes/Web/slim/vendor/slim/slim/Slim/MiddlewareDispatcher.php on line 180
File: /Volumes/Web/slim/vendor/slim/csrf/src/Guard.php
这是我的代码:
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Csrf\Guard;
require __DIR__ . '/../vendor/autoload.php';
/**
* Instantiate App
*
* In order for the factory to work you need to ensure you have installed
* a supported PSR-7 implementation of your choice e.g.: Slim PSR-7 and a supported
* ServerRequest creator (included with Slim PSR-7)
*/
$app = AppFactory::create();
$app->add(Guard::class);
// Add Routing Middleware
$app->addRoutingMiddleware();
/*
* Add Error Handling Middleware
*
* @param bool $displayErrorDetails -> Should be set to false in production
* @param bool $logErrors -> Parameter is passed to the default ErrorHandler
* @param bool $logErrorDetails -> Display error details in error log
* which can be replaced by a callable of your choice.
* Note: This middleware should be added last. It will not handle any exceptions/errors
* for middleware added after it.
*/
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// Define app routes
$app->get('/', function (Request $request, Response $response, $args) {
$response->getBody()->write('Hello');
return $response;
});
// Run app
$app->run();
非常感谢任何帮助!谢谢!
相关位是:
$app->add(Guard::class);
中间件回调的签名已更改。在 Slim/3 它曾经像 this:
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
): ResponseInterface
... 然后该方法必须像 $next($request, $response)
.
一样调用 $next
在Slim/4中是这样的:
public function __invoke(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface
.. 而对 $handler
的内部调用是 $handler->handle($request)
.
库似乎没有为 Slim/4 更新。它在 composer.json and mentions in README.md. Perhaps it isn't very difficult to either fix the library or write a compatible wrapper on top of it but if you aren't familiar with the overall ecosystem it's probably easier to install a replacement.
中将 Slim/3 声明为 dev (?) 依赖项
该软件包与 Slim4 不兼容。我写了一个包装器,所以你可以使用它。
`
<?php
declare(strict_types=1);
namespace App\Application\Middleware;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Csrf\Guard as Guard;
class CsrfMiddleware extends Guard implements Middleware
{
/**
* Process middleware
*
* @param ServerRequestInterface $request request object
* @param RequestHandlerInterface $handler handler object
*
* @return ResponseInterface response object
*/
public function process(Request $request, RequestHandler $handler): Response
{
$this->validateStorage();
// Validate POST, PUT, DELETE, PATCH requests
if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$body = $request->getParsedBody();
$body = $body ? (array) $body : [];
$name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
$value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$request = $this->generateNewToken($request);
$failureCallable = $this->getFailureCallable();
return $failureCallable($request, $handler);
}
}
// Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
$request = $this->generateNewToken($request);
} elseif ($this->persistentTokenMode) {
$pair = $this->loadLastKeyPair() ? $this->keyPair : $this->generateToken();
$request = $this->attachRequestAttributes($request, $pair);
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $handler->handle($request);
}
/**
* Getter for failureCallable
*
* @return callable|\Closure
*/
public function getFailureCallable()
{
if (is_null($this->failureCallable)) {
$this->failureCallable = function (Request $request, RequestHandler $handler): Response {
$response = $handler->handle($request);
$stream = $response->getBody();
$stream->write('CSRF fail');
return $response->withStatus(400);
};
}
return $this->failureCallable;
}
}
`
Slim 4 已经在这里,我正在尝试迁移到 Slim 4。一切都很好,但是 CSRF returns 在我尝试实现它时出现错误。我尝试了最简单的设置,但出现此错误:
Message: Argument 2 passed to Slim\Csrf\Guard::__invoke() must be an instance of Psr\Http\Message\ResponseInterface, instance of Slim\Routing\RouteRunner given, called in /Volumes/Web/slim/vendor/slim/slim/Slim/MiddlewareDispatcher.php on line 180
File: /Volumes/Web/slim/vendor/slim/csrf/src/Guard.php
这是我的代码:
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Csrf\Guard;
require __DIR__ . '/../vendor/autoload.php';
/**
* Instantiate App
*
* In order for the factory to work you need to ensure you have installed
* a supported PSR-7 implementation of your choice e.g.: Slim PSR-7 and a supported
* ServerRequest creator (included with Slim PSR-7)
*/
$app = AppFactory::create();
$app->add(Guard::class);
// Add Routing Middleware
$app->addRoutingMiddleware();
/*
* Add Error Handling Middleware
*
* @param bool $displayErrorDetails -> Should be set to false in production
* @param bool $logErrors -> Parameter is passed to the default ErrorHandler
* @param bool $logErrorDetails -> Display error details in error log
* which can be replaced by a callable of your choice.
* Note: This middleware should be added last. It will not handle any exceptions/errors
* for middleware added after it.
*/
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// Define app routes
$app->get('/', function (Request $request, Response $response, $args) {
$response->getBody()->write('Hello');
return $response;
});
// Run app
$app->run();
非常感谢任何帮助!谢谢!
相关位是:
$app->add(Guard::class);
中间件回调的签名已更改。在 Slim/3 它曾经像 this:
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
): ResponseInterface
... 然后该方法必须像 $next($request, $response)
.
$next
在Slim/4中是这样的:
public function __invoke(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface
.. 而对 $handler
的内部调用是 $handler->handle($request)
.
库似乎没有为 Slim/4 更新。它在 composer.json and mentions in README.md. Perhaps it isn't very difficult to either fix the library or write a compatible wrapper on top of it but if you aren't familiar with the overall ecosystem it's probably easier to install a replacement.
中将 Slim/3 声明为 dev (?) 依赖项该软件包与 Slim4 不兼容。我写了一个包装器,所以你可以使用它。
`
<?php
declare(strict_types=1);
namespace App\Application\Middleware;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Csrf\Guard as Guard;
class CsrfMiddleware extends Guard implements Middleware
{
/**
* Process middleware
*
* @param ServerRequestInterface $request request object
* @param RequestHandlerInterface $handler handler object
*
* @return ResponseInterface response object
*/
public function process(Request $request, RequestHandler $handler): Response
{
$this->validateStorage();
// Validate POST, PUT, DELETE, PATCH requests
if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
$body = $request->getParsedBody();
$body = $body ? (array) $body : [];
$name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
$value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$request = $this->generateNewToken($request);
$failureCallable = $this->getFailureCallable();
return $failureCallable($request, $handler);
}
}
// Generate new CSRF token if persistentTokenMode is false, or if a valid keyPair has not yet been stored
if (!$this->persistentTokenMode || !$this->loadLastKeyPair()) {
$request = $this->generateNewToken($request);
} elseif ($this->persistentTokenMode) {
$pair = $this->loadLastKeyPair() ? $this->keyPair : $this->generateToken();
$request = $this->attachRequestAttributes($request, $pair);
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $handler->handle($request);
}
/**
* Getter for failureCallable
*
* @return callable|\Closure
*/
public function getFailureCallable()
{
if (is_null($this->failureCallable)) {
$this->failureCallable = function (Request $request, RequestHandler $handler): Response {
$response = $handler->handle($request);
$stream = $response->getBody();
$stream->write('CSRF fail');
return $response->withStatus(400);
};
}
return $this->failureCallable;
}
}
`