bug #28241 [HttpKernel] fix forwarding trusted headers as server parameters (nicolas-grekas)

This PR was merged into the 2.8 branch.

Discussion
----------

[HttpKernel] fix forwarding trusted headers as server parameters

| Q             | A
| ------------- | ---
| Branch?       | 2.8
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #28233, #28226, #28225, #28240
| License       | MIT
| Doc PR        | -

Commits
-------

92953485a5 [HttpKernel] fix forwarding trusted headers as server parameters
This commit is contained in:
Nicolas Grekas 2018-08-24 16:33:48 +02:00
commit 2554ad0698
4 changed files with 22 additions and 7 deletions

View File

@ -1991,7 +1991,7 @@ class Request
if ($i) { if ($i) {
$clientIps[$key] = $clientIp = substr($clientIp, 0, $i); $clientIps[$key] = $clientIp = substr($clientIp, 0, $i);
} }
} elseif ('[' == $clientIp[0]) { } elseif (0 === strpos($clientIp, '[')) {
// Strip brackets and :port from IPv6 addresses. // Strip brackets and :port from IPv6 addresses.
$i = strpos($clientIp, ']', 1); $i = strpos($clientIp, ']', 1);
$clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1);

View File

@ -868,7 +868,7 @@ class RequestTest extends TestCase
public function getClientIpsProvider() public function getClientIpsProvider()
{ {
// $expected $remoteAddr $httpForwardedFor $trustedProxies // $expected $remoteAddr $httpForwardedFor $trustedProxies
return array( return array(
// simple IPv4 // simple IPv4
array(array('88.88.88.88'), '88.88.88.88', null, null), array(array('88.88.88.88'), '88.88.88.88', null, null),
@ -882,8 +882,8 @@ class RequestTest extends TestCase
// forwarded for with remote IPv4 addr not trusted // forwarded for with remote IPv4 addr not trusted
array(array('127.0.0.1'), '127.0.0.1', '88.88.88.88', null), array(array('127.0.0.1'), '127.0.0.1', '88.88.88.88', null),
// forwarded for with remote IPv4 addr trusted // forwarded for with remote IPv4 addr trusted + comma
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1')), array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88,', array('127.0.0.1')),
// forwarded for with remote IPv4 and all FF addrs trusted // forwarded for with remote IPv4 and all FF addrs trusted
array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1', '88.88.88.88')), array(array('88.88.88.88'), '127.0.0.1', '88.88.88.88', array('127.0.0.1', '88.88.88.88')),
// forwarded for with remote IPv4 range trusted // forwarded for with remote IPv4 range trusted

View File

@ -43,6 +43,7 @@ class SubRequestHandler
if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) { if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) {
foreach (array_filter($trustedHeaders) as $name) { foreach (array_filter($trustedHeaders) as $name) {
$request->headers->remove($name); $request->headers->remove($name);
$request->server->remove('HTTP_'.strtoupper(str_replace('-', '_', $name)));
} }
} }
@ -61,13 +62,16 @@ class SubRequestHandler
// set trusted values, reusing as much as possible the global trusted settings // set trusted values, reusing as much as possible the global trusted settings
if ($name = $trustedHeaders[Request::HEADER_FORWARDED]) { if ($name = $trustedHeaders[Request::HEADER_FORWARDED]) {
$trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme());
$request->headers->set($name, implode(', ', $trustedValues)); $request->headers->set($name, $v = implode(', ', $trustedValues));
$request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v);
} }
if ($name = $trustedHeaders[Request::HEADER_CLIENT_IP]) { if ($name = $trustedHeaders[Request::HEADER_CLIENT_IP]) {
$request->headers->set($name, implode(', ', $trustedIps)); $request->headers->set($name, $v = implode(', ', $trustedIps));
$request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v);
} }
if (!$name && !$trustedHeaders[Request::HEADER_FORWARDED]) { if (!$name && !$trustedHeaders[Request::HEADER_FORWARDED]) {
$request->headers->set('X-Forwarded-For', implode(', ', $trustedIps)); $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps));
$request->server->set('HTTP_X_FORWARDED_FOR', $v);
Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR');
} }

View File

@ -60,6 +60,8 @@ class InlineFragmentRendererTest extends TestCase
$subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en')); $subRequest->attributes->replace(array('object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en'));
$subRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $subRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$subRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); $subRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
$subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$subRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest)); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
@ -91,6 +93,7 @@ class InlineFragmentRendererTest extends TestCase
$expectedSubRequest = Request::create('/'); $expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent()); $this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
@ -178,8 +181,10 @@ class InlineFragmentRendererTest extends TestCase
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"'); $expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
if (Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)) { if (Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)) {
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
} }
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
@ -203,6 +208,8 @@ class InlineFragmentRendererTest extends TestCase
$expectedSubRequest = Request::create('/'); $expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*')); $request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*'));
@ -216,6 +223,8 @@ class InlineFragmentRendererTest extends TestCase
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1'); $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
Request::setTrustedProxies(array('1.1.1.1')); Request::setTrustedProxies(array('1.1.1.1'));
@ -235,6 +244,8 @@ class InlineFragmentRendererTest extends TestCase
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1'); $expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
$expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http')); $expectedSubRequest->headers->set('forwarded', array('for="127.0.0.1";host="localhost";proto=http'));
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
Request::setTrustedProxies(array('1.1.1.1/24')); Request::setTrustedProxies(array('1.1.1.1/24'));