mirror of
https://github.com/flarum/framework.git
synced 2025-03-10 20:31:24 +08:00
Implement middleware for CSRF token verification
This fixes a rather large oversight in Flarum's codebase, which was that we had no explicit CSRF protection using the traditional token approach. The JS frontend was actually sending these tokens, but the backend did not require them.
This commit is contained in:
parent
69fdd82ffc
commit
aa43d1475e
@ -61,6 +61,7 @@ class AdminServiceProvider extends AbstractServiceProvider
|
||||
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
$pipe->pipe($app->make(Middleware\RequireAdministrateAbility::class));
|
||||
|
||||
|
@ -57,6 +57,7 @@ class ApiServiceProvider extends AbstractServiceProvider
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithHeader::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
|
||||
event(new ConfigureMiddleware($pipe, 'api'));
|
||||
|
@ -68,6 +68,7 @@ class ForumServiceProvider extends AbstractServiceProvider
|
||||
$pipe->pipe($app->make(HttpMiddleware\StartSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\RememberFromCookie::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\AuthenticateWithSession::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\CheckCsrfToken::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\SetLocale::class));
|
||||
$pipe->pipe($app->make(HttpMiddleware\ShareErrorsFromSession::class));
|
||||
|
||||
|
@ -44,6 +44,8 @@ class AuthenticateWithHeader implements Middleware
|
||||
$token->touch();
|
||||
|
||||
$actor = $token->user;
|
||||
|
||||
$request = $request->withAttribute('bypassCsrfToken', true);
|
||||
}
|
||||
|
||||
if (isset($actor)) {
|
||||
|
46
framework/core/src/Http/Middleware/CheckCsrfToken.php
Normal file
46
framework/core/src/Http/Middleware/CheckCsrfToken.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Http\Middleware;
|
||||
|
||||
use Flarum\Http\Exception\TokenMismatchException;
|
||||
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 Handler;
|
||||
|
||||
class CheckCsrfToken implements Middleware
|
||||
{
|
||||
public function process(Request $request, Handler $handler): Response
|
||||
{
|
||||
if (in_array($request->getMethod(), ['GET', 'HEAD', 'OPTIONS'])) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
if ($request->getAttribute('bypassCsrfToken', false)) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
if ($this->tokensMatch($request)) {
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
throw new TokenMismatchException('CSRF token did not match');
|
||||
}
|
||||
|
||||
private function tokensMatch(Request $request): bool
|
||||
{
|
||||
$expected = (string) $request->getAttribute('session')->token();
|
||||
$provided = $request->getHeaderLine('X-CSRF-Token'); // TODO: Use form field, if provided
|
||||
|
||||
return hash_equals($expected, $provided);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user