Skip to content

Commit 6251c4e

Browse files
committed
feature #38954 [HttpFundation][FrameworkBundle] Deprecate the HEADER_X_FORWARDED_ALL constant (jderusse)
This PR was merged into the 5.2-dev branch. Discussion ---------- [HttpFundation][FrameworkBundle] Deprecate the HEADER_X_FORWARDED_ALL constant | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | - | License | MIT | Doc PR | TODO The `HEADER_X_FORWARDED_ALL` implicitly trust the `x-forwarded-host` header, leading to possible host header attack (as warned in the [documentation](https://symfony.com/doc/current/reference/configuration/framework.html#trusted-hosts).) Moreover, this `HEADER_X_FORWARDED_ALL` does not really fowards **all** headers, as ti does not supports `X-Forwarded-Prefix` headers. This PR deprecate the constant and the new framework bundle configuration. It will be removed in 6.0. People have to use: either: - `Request::setTrustedProxies(['1.2.3.4'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);` - `Request::setTrustedProxies(['1.2.3.4'], Request::HEADER_X_FORWARDED_TRAEFIK);` - `framework.trusted_headers: [x-forwarded-for, x-forwarded-host, x-forwarded-port, x-forwarded-proto]` Commits ------- 7cf4dd6 Deprecate HEADER_X_FORWARDED_ALL constant
2 parents 2d7e0b0 + 7cf4dd6 commit 6251c4e

File tree

10 files changed

+48
-28
lines changed

10 files changed

+48
-28
lines changed

UPGRADE-5.2.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ HttpFoundation
4343
--------------
4444

4545
* Deprecated not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()`; wrap your filter in a closure instead.
46+
* Deprecated the `Request::HEADER_X_FORWARDED_ALL` constant, use either `Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO` or `Request::HEADER_X_FORWARDED_AWS_ELB` or `Request::HEADER_X_FORWARDED_TRAEFIK`constants instead.
4647

4748
Lock
4849
----

UPGRADE-6.0.md

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ HttpFoundation
6767
`RedirectResponse::create()`, and `StreamedResponse::create()` methods (use
6868
`__construct()` instead)
6969
* Not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()` throws an `InvalidArgumentException`; wrap your filter in a closure instead.
70+
* Removed the `Request::HEADER_X_FORWARDED_ALL` constant, use either `Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO` or `Request::HEADER_X_FORWARDED_AWS_ELB` or `Request::HEADER_X_FORWARDED_TRAEFIK`constants instead.
7071

7172
HttpKernel
7273
----------

src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public function testUsesRequestServerData()
3838

3939
public function testUseRequestClientIp()
4040
{
41-
Request::setTrustedProxies(['192.168.0.1'], Request::HEADER_X_FORWARDED_ALL);
41+
Request::setTrustedProxies(['192.168.0.1'], Request::HEADER_X_FORWARDED_FOR);
4242
[$event, $server] = $this->createRequestEvent(['X_FORWARDED_FOR' => '192.168.0.2']);
4343

4444
$processor = new WebProcessor();

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,12 @@ public function getConfigTreeBuilder()
9292
->arrayNode('trusted_headers')
9393
->fixXmlConfig('trusted_header')
9494
->performNoDeepMerging()
95-
->defaultValue(['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'])
95+
->defaultValue(['x-forwarded-for', 'x-forwarded-port', 'x-forwarded-proto'])
9696
->beforeNormalization()->ifString()->then(function ($v) { return $v ? array_map('trim', explode(',', $v)) : []; })->end()
9797
->enumPrototype()
9898
->values([
9999
'forwarded',
100100
'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port',
101-
'x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix',
102101
])
103102
->end()
104103
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

-7
Original file line numberDiff line numberDiff line change
@@ -2294,13 +2294,6 @@ private function resolveTrustedHeaders(array $headers): int
22942294
case 'x-forwarded-host': $trustedHeaders |= Request::HEADER_X_FORWARDED_HOST; break;
22952295
case 'x-forwarded-proto': $trustedHeaders |= Request::HEADER_X_FORWARDED_PROTO; break;
22962296
case 'x-forwarded-port': $trustedHeaders |= Request::HEADER_X_FORWARDED_PORT; break;
2297-
case '!x-forwarded-host': $trustedHeaders &= ~Request::HEADER_X_FORWARDED_HOST; break;
2298-
case 'x-forwarded-all':
2299-
if (!\in_array('!x-forwarded-prefix', $headers)) {
2300-
throw new LogicException('When using "x-forwarded-all" in "framework.trusted_headers", "!x-forwarded-prefix" must be explicitly listed until support for X-Forwarded-Prefix is implemented.');
2301-
}
2302-
$trustedHeaders |= Request::HEADER_X_FORWARDED_ALL;
2303-
break;
23042297
}
23052298
}
23062299

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,9 @@ protected static function getBundleDefaultConfig()
341341
'secret' => 's3cr3t',
342342
'trusted_hosts' => [],
343343
'trusted_headers' => [
344-
'x-forwarded-all',
345-
'!x-forwarded-host',
346-
'!x-forwarded-prefix',
344+
'x-forwarded-for',
345+
'x-forwarded-port',
346+
'x-forwarded-proto',
347347
],
348348
'csrf_protection' => [
349349
'enabled' => false,

src/Symfony/Component/HttpFoundation/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CHANGELOG
1111
* added `Request::toArray()` to parse a JSON request body to an array
1212
* added `RateLimiter\RequestRateLimiterInterface` and `RateLimiter\AbstractRequestRateLimiter`
1313
* deprecated not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()`; wrap your filter in a closure instead.
14+
* Deprecated the `Request::HEADER_X_FORWARDED_ALL` constant, use either `HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO` or `HEADER_X_FORWARDED_AWS_ELB` or `HEADER_X_FORWARDED_TRAEFIK` constants instead.
15+
1416

1517
5.1.0
1618
-----

src/Symfony/Component/HttpFoundation/Request.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ class Request
4747
const HEADER_X_FORWARDED_PORT = 0b010000;
4848
const HEADER_X_FORWARDED_PREFIX = 0b100000;
4949

50-
const HEADER_X_FORWARDED_ALL = 0b011110; // All "X-Forwarded-*" headers sent by "usual" reverse proxy
51-
const HEADER_X_FORWARDED_AWS_ELB = 0b011010; // AWS ELB doesn't send X-Forwarded-Host
52-
const HEADER_X_FORWARDED_TRAEFIK = 0b111110; // All "X-Forwarded-*" headers sent by Traefik reverse proxy
50+
/** @deprecated since Symfony 5.2, use either "HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO" or "HEADER_X_FORWARDED_AWS_ELB" or "HEADER_X_FORWARDED_TRAEFIK" constants instead. */
51+
const HEADER_X_FORWARDED_ALL = 0b1011110; // All "X-Forwarded-*" headers sent by "usual" reverse proxy
52+
const HEADER_X_FORWARDED_AWS_ELB = 0b0011010; // AWS ELB doesn't send X-Forwarded-Host
53+
const HEADER_X_FORWARDED_TRAEFIK = 0b0111110; // All "X-Forwarded-*" headers sent by Traefik reverse proxy
5354

5455
const METHOD_HEAD = 'HEAD';
5556
const METHOD_GET = 'GET';
@@ -593,6 +594,9 @@ public function overrideGlobals()
593594
*/
594595
public static function setTrustedProxies(array $proxies, int $trustedHeaderSet)
595596
{
597+
if (self::HEADER_X_FORWARDED_ALL === $trustedHeaderSet) {
598+
trigger_deprecation('symfony/http-fundation', '5.2', 'The "HEADER_X_FORWARDED_ALL" constant is deprecated, use either "HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO" or "HEADER_X_FORWARDED_AWS_ELB" or "HEADER_X_FORWARDED_TRAEFIK" constants instead.');
599+
}
596600
self::$trustedProxies = array_reduce($proxies, function ($proxies, $proxy) {
597601
if ('REMOTE_ADDR' !== $proxy) {
598602
$proxies[] = $proxy;

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

+31-11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\HttpFoundation\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\HttpFoundation\Exception\JsonException;
1617
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
1718
use Symfony\Component\HttpFoundation\InputBag;
@@ -22,6 +23,8 @@
2223

2324
class RequestTest extends TestCase
2425
{
26+
use ExpectDeprecationTrait;
27+
2528
protected function tearDown(): void
2629
{
2730
Request::setTrustedProxies([], -1);
@@ -867,7 +870,7 @@ public function testGetPort()
867870

868871
$this->assertEquals(80, $port, 'Without trusted proxies FORWARDED_PROTO and FORWARDED_PORT are ignored.');
869872

870-
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL);
873+
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_PORT);
871874
$request = Request::create('http://example.com', 'GET', [], [], [], [
872875
'HTTP_X_FORWARDED_PROTO' => 'https',
873876
'HTTP_X_FORWARDED_PORT' => '8443',
@@ -1091,7 +1094,7 @@ public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXFor
10911094
'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
10921095
];
10931096

1094-
Request::setTrustedProxies(['88.88.88.88'], Request::HEADER_X_FORWARDED_ALL | Request::HEADER_FORWARDED);
1097+
Request::setTrustedProxies(['88.88.88.88'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_FORWARDED);
10951098

10961099
$request->initialize([], [], [], [], [], $server);
10971100

@@ -1349,7 +1352,7 @@ public function testOverrideGlobals()
13491352

13501353
$request->headers->set('X_FORWARDED_PROTO', 'https');
13511354

1352-
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL);
1355+
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_PROTO);
13531356
$this->assertFalse($request->isSecure());
13541357
$request->server->set('REMOTE_ADDR', '1.1.1.1');
13551358
$this->assertTrue($request->isSecure());
@@ -1830,7 +1833,7 @@ private function getRequestInstanceForClientIpTests(string $remoteAddr, ?string
18301833
}
18311834

18321835
if ($trustedProxies) {
1833-
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL);
1836+
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_FOR);
18341837
}
18351838

18361839
$request->initialize([], [], [], [], [], $server);
@@ -1873,35 +1876,35 @@ public function testTrustedProxiesXForwardedFor()
18731876
$this->assertFalse($request->isSecure());
18741877

18751878
// disabling proxy trusting
1876-
Request::setTrustedProxies([], Request::HEADER_X_FORWARDED_ALL);
1879+
Request::setTrustedProxies([], Request::HEADER_X_FORWARDED_FOR);
18771880
$this->assertEquals('3.3.3.3', $request->getClientIp());
18781881
$this->assertEquals('example.com', $request->getHost());
18791882
$this->assertEquals(80, $request->getPort());
18801883
$this->assertFalse($request->isSecure());
18811884

18821885
// request is forwarded by a non-trusted proxy
1883-
Request::setTrustedProxies(['2.2.2.2'], Request::HEADER_X_FORWARDED_ALL);
1886+
Request::setTrustedProxies(['2.2.2.2'], Request::HEADER_X_FORWARDED_FOR);
18841887
$this->assertEquals('3.3.3.3', $request->getClientIp());
18851888
$this->assertEquals('example.com', $request->getHost());
18861889
$this->assertEquals(80, $request->getPort());
18871890
$this->assertFalse($request->isSecure());
18881891

18891892
// trusted proxy via setTrustedProxies()
1890-
Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL);
1893+
Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);
18911894
$this->assertEquals('1.1.1.1', $request->getClientIp());
18921895
$this->assertEquals('foo.example.com', $request->getHost());
18931896
$this->assertEquals(443, $request->getPort());
18941897
$this->assertTrue($request->isSecure());
18951898

18961899
// trusted proxy via setTrustedProxies()
1897-
Request::setTrustedProxies(['3.3.3.4', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL);
1900+
Request::setTrustedProxies(['3.3.3.4', '2.2.2.2'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO);
18981901
$this->assertEquals('3.3.3.3', $request->getClientIp());
18991902
$this->assertEquals('example.com', $request->getHost());
19001903
$this->assertEquals(80, $request->getPort());
19011904
$this->assertFalse($request->isSecure());
19021905

19031906
// check various X_FORWARDED_PROTO header values
1904-
Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL);
1907+
Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_PROTO);
19051908
$request->headers->set('X_FORWARDED_PROTO', 'ssl');
19061909
$this->assertTrue($request->isSecure());
19071910

@@ -2377,7 +2380,7 @@ public function testTrustedPort()
23772380

23782381
public function testTrustedPortDoesNotDefaultToZero()
23792382
{
2380-
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL);
2383+
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_FOR);
23812384

23822385
$request = Request::create('/');
23832386
$request->server->set('REMOTE_ADDR', '1.1.1.1');
@@ -2393,7 +2396,7 @@ public function testTrustedPortDoesNotDefaultToZero()
23932396
public function testTrustedProxiesRemoteAddr($serverRemoteAddr, $trustedProxies, $result)
23942397
{
23952398
$_SERVER['REMOTE_ADDR'] = $serverRemoteAddr;
2396-
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL);
2399+
Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_FOR);
23972400
$this->assertSame($result, Request::getTrustedProxies());
23982401
}
23992402

@@ -2464,6 +2467,23 @@ public function preferSafeContentData()
24642467
],
24652468
];
24662469
}
2470+
2471+
/**
2472+
* @group legacy
2473+
*/
2474+
public function testXForwarededAllConstantDeprecated()
2475+
{
2476+
$this->expectDeprecation('Since symfony/http-fundation 5.2: The "HEADER_X_FORWARDED_ALL" constant is deprecated, use either "HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO" or "HEADER_X_FORWARDED_AWS_ELB" or "HEADER_X_FORWARDED_TRAEFIK" constants instead.');
2477+
2478+
Request::setTrustedProxies([], Request::HEADER_X_FORWARDED_ALL);
2479+
}
2480+
2481+
public function testReservedFlags()
2482+
{
2483+
foreach ((new \ReflectionClass(Request::class))->getConstants() as $constant => $value) {
2484+
$this->assertNotSame(0b10000000, $value, sprintf('The constant "%s" should not use the reserved value "0b10000000".', $constant));
2485+
}
2486+
}
24672487
}
24682488

24692489
class RequestContentProxy extends Request

src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ public function testClientIpIsAlwaysLocalhostForForwardedRequests()
13611361
*/
13621362
public function testHttpCacheIsSetAsATrustedProxy(array $existing)
13631363
{
1364-
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL);
1364+
Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_FOR);
13651365

13661366
$this->setNextResponse();
13671367
$this->request('GET', '/', ['REMOTE_ADDR' => '10.0.0.1']);

0 commit comments

Comments
 (0)