1
0
mirror of https://github.com/flarum/core.git synced 2025-08-05 16:07:34 +02:00

fix: Logout controller allows open redirects (#4091)

Co-authored-by: IanM <16573496+imorland@users.noreply.github.com>
This commit is contained in:
Sami Mazouz
2024-10-24 18:47:06 +01:00
committed by GitHub
parent eae355ddaf
commit 3b66925a66

View File

@@ -9,6 +9,7 @@
namespace Flarum\Forum\Controller; namespace Flarum\Forum\Controller;
use Flarum\Foundation\Config;
use Flarum\Http\Rememberer; use Flarum\Http\Rememberer;
use Flarum\Http\RequestUtil; use Flarum\Http\RequestUtil;
use Flarum\Http\SessionAuthenticator; use Flarum\Http\SessionAuthenticator;
@@ -19,6 +20,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\Diactoros\Response\RedirectResponse; use Laminas\Diactoros\Response\RedirectResponse;
use Laminas\Diactoros\Uri;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
@@ -30,7 +32,8 @@ class LogOutController implements RequestHandlerInterface
protected SessionAuthenticator $authenticator, protected SessionAuthenticator $authenticator,
protected Rememberer $rememberer, protected Rememberer $rememberer,
protected Factory $view, protected Factory $view,
protected UrlGenerator $url protected UrlGenerator $url,
protected Config $config
) { ) {
} }
@@ -38,12 +41,14 @@ class LogOutController implements RequestHandlerInterface
{ {
$session = $request->getAttribute('session'); $session = $request->getAttribute('session');
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);
$base = $this->url->to('forum')->base();
$url = Arr::get($request->getQueryParams(), 'return', $this->url->to('forum')->base()); $returnUrl = Arr::get($request->getQueryParams(), 'return');
$return = $this->sanitizeReturnUrl((string) $returnUrl, $base);
// If there is no user logged in, return to the index. // If there is no user logged in, return to the index or the return url if it's set.
if ($actor->isGuest()) { if ($actor->isGuest()) {
return new RedirectResponse($url); return new RedirectResponse($return);
} }
// If a valid CSRF token hasn't been provided, show a view which will // If a valid CSRF token hasn't been provided, show a view which will
@@ -51,16 +56,14 @@ class LogOutController implements RequestHandlerInterface
$csrfToken = $session->token(); $csrfToken = $session->token();
if (Arr::get($request->getQueryParams(), 'token') !== $csrfToken) { if (Arr::get($request->getQueryParams(), 'token') !== $csrfToken) {
$return = Arr::get($request->getQueryParams(), 'return');
$view = $this->view->make('flarum.forum::log-out') $view = $this->view->make('flarum.forum::log-out')
->with('url', $this->url->to('forum')->route('logout').'?token='.$csrfToken.($return ? '&return='.urlencode($return) : '')); ->with('url', $this->url->to('forum')->route('logout').'?token='.$csrfToken.($returnUrl ? '&return='.urlencode($return) : ''));
return new HtmlResponse($view->render()); return new HtmlResponse($view->render());
} }
$accessToken = $session->get('access_token'); $accessToken = $session->get('access_token');
$response = new RedirectResponse($url); $response = new RedirectResponse($return);
$this->authenticator->logOut($session); $this->authenticator->logOut($session);
@@ -70,4 +73,33 @@ class LogOutController implements RequestHandlerInterface
return $this->rememberer->forget($response); return $this->rememberer->forget($response);
} }
protected function sanitizeReturnUrl(string $url, string $base): Uri
{
if (empty($url)) {
return new Uri($base);
}
try {
$parsedUrl = new Uri($url);
} catch (\InvalidArgumentException $e) {
return new Uri($base);
}
if (in_array($parsedUrl->getHost(), $this->getAllowedRedirectDomains())) {
return $parsedUrl;
}
return new Uri($base);
}
protected function getAllowedRedirectDomains(): array
{
$forumUri = $this->config->url();
return array_merge(
[$forumUri->getHost()],
$this->config->offsetGet('redirectDomains') ?? []
);
}
} }