Fixes wrong IP address when using a reverse proxy (#2236)

Added reverse proxy support to preserve forwarded IPs
This commit is contained in:
Jake Esser 2020-07-22 14:55:44 +02:00 committed by GitHub
parent 89a2a9786e
commit a6cb962f97
7 changed files with 128 additions and 2 deletions

View File

@ -25,6 +25,7 @@ use Flarum\Http\RouteHandlerFactory;
use Flarum\Http\UrlGenerator;
use Flarum\Locale\LocaleManager;
use Flarum\Settings\Event\Saved;
use Illuminate\Support\Arr;
use Laminas\Stratigility\MiddlewarePipe;
class AdminServiceProvider extends AbstractServiceProvider
@ -48,6 +49,7 @@ class AdminServiceProvider extends AbstractServiceProvider
$this->app->singleton('flarum.admin.middleware', function () {
return [
'flarum.admin.error_handler',
'flarum.admin.proxy_middleware',
HttpMiddleware\ParseJsonBody::class,
HttpMiddleware\StartSession::class,
HttpMiddleware\RememberFromCookie::class,
@ -66,6 +68,15 @@ class AdminServiceProvider extends AbstractServiceProvider
);
});
$this->app->bind('flarum.admin.proxy_middleware', function () {
$config = $this->app->make('flarum.config');
return new HttpMiddleware\ProxyAddress(
Arr::get($config, 'reverse_proxy.enabled', false),
Arr::get($config, 'reverse_proxy.allowed', ['127.0.0.1'])
);
});
$this->app->singleton('flarum.admin.handler', function () {
$pipe = new MiddlewarePipe;

View File

@ -22,6 +22,7 @@ use Flarum\Http\Middleware as HttpMiddleware;
use Flarum\Http\RouteCollection;
use Flarum\Http\RouteHandlerFactory;
use Flarum\Http\UrlGenerator;
use Illuminate\Support\Arr;
use Laminas\Stratigility\MiddlewarePipe;
class ApiServiceProvider extends AbstractServiceProvider
@ -45,6 +46,7 @@ class ApiServiceProvider extends AbstractServiceProvider
$this->app->singleton('flarum.api.middleware', function () {
return [
'flarum.api.error_handler',
'flarum.api.proxy_middleware',
HttpMiddleware\ParseJsonBody::class,
Middleware\FakeHttpMethods::class,
HttpMiddleware\StartSession::class,
@ -64,6 +66,15 @@ class ApiServiceProvider extends AbstractServiceProvider
);
});
$this->app->bind('flarum.api.proxy_middleware', function () {
$config = $this->app->make('flarum.config');
return new HttpMiddleware\ProxyAddress(
Arr::get($config, 'reverse_proxy.enabled', false),
Arr::get($config, 'reverse_proxy.allowed', ['127.0.0.1'])
);
});
$this->app->singleton('flarum.api.handler', function () {
$pipe = new MiddlewarePipe;

View File

@ -62,7 +62,7 @@ class CreateDiscussionController extends AbstractCreateController
protected function data(ServerRequestInterface $request, Document $document)
{
$actor = $request->getAttribute('actor');
$ipAddress = Arr::get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
$ipAddress = $request->getAttribute('ipAddress');
if (! $request->getAttribute('bypassFloodgate')) {
$this->floodgate->assertNotFlooding($actor);

View File

@ -63,7 +63,7 @@ class CreatePostController extends AbstractCreateController
$actor = $request->getAttribute('actor');
$data = Arr::get($request->getParsedBody(), 'data', []);
$discussionId = Arr::get($data, 'relationships.discussion.data.id');
$ipAddress = Arr::get($request->getServerParams(), 'REMOTE_ADDR', '127.0.0.1');
$ipAddress = $request->getAttribute('ipAddress');
if (! $request->getAttribute('bypassFloodgate')) {
$this->floodgate->assertNotFlooding($actor);

View File

@ -29,6 +29,7 @@ use Flarum\Locale\LocaleManager;
use Flarum\Settings\Event\Saved;
use Flarum\Settings\Event\Saving;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Support\Arr;
use Laminas\Stratigility\MiddlewarePipe;
use Symfony\Component\Translation\TranslatorInterface;
@ -57,6 +58,7 @@ class ForumServiceProvider extends AbstractServiceProvider
$this->app->singleton('flarum.forum.middleware', function () {
return [
'flarum.forum.error_handler',
'flarum.forum.proxy_middleware',
HttpMiddleware\ParseJsonBody::class,
HttpMiddleware\CollectGarbage::class,
HttpMiddleware\StartSession::class,
@ -76,6 +78,15 @@ class ForumServiceProvider extends AbstractServiceProvider
);
});
$this->app->bind('flarum.forum.proxy_middleware', function () {
$config = $this->app->make('flarum.config');
return new HttpMiddleware\ProxyAddress(
Arr::get($config, 'reverse_proxy.enabled', false),
Arr::get($config, 'reverse_proxy.allowed', ['127.0.0.1'])
);
});
$this->app->singleton('flarum.forum.handler', function () {
$pipe = new MiddlewarePipe;

View File

@ -0,0 +1,21 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Http\Exception;
use Exception;
use Flarum\Foundation\KnownError;
class ProxyNotAllowedException extends Exception implements KnownError
{
public function getType(): string
{
return 'reverse_proxy_not_allowed';
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Http\Middleware;
use Flarum\Http\Exception\ProxyNotAllowedException;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface;
class ProxyAddress implements Middleware
{
/**
* @var bool
*/
protected $enabled;
/**
* @var array
*/
protected $allowedAddresses;
/**
* @param bool $enabled
* @param array $allowedAddresses
*/
public function __construct($enabled, $allowedAddresses)
{
$this->enabled = $enabled;
$this->allowedAddresses = $allowedAddresses;
}
private function wildcardMatch(string $ipAddress): bool
{
foreach ($this->allowedAddresses as $allowedAddress) {
if (fnmatch($allowedAddress, $ipAddress)) {
return true;
}
}
return false;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$serverParams = $request->getServerParams();
$ipAddress = Arr::get($serverParams, 'REMOTE_ADDR', '127.0.0.1');
if ($this->enabled) {
if ($this->wildcardMatch($ipAddress)) {
// standard header for proxies, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
$ipAddress = Arr::get($serverParams, 'X_FORWARDED_FOR', $ipAddress);
$ipAddress = Arr::get($serverParams, 'HTTP_CLIENT_IP', $ipAddress);
$ipAddress = Arr::get($serverParams, 'X_PROXYUSER_IP', $ipAddress);
} else {
throw new ProxyNotAllowedException();
}
}
$request = $request->withAttribute('ipAddress', $ipAddress);
return $handler->handle($request);
}
}