From ec85d5d7161a20452eb35a8cc9b01a685a887f1e Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 01:46:45 +0200 Subject: [PATCH 1/8] Implemented RFC 7239 - " Forwarded HTTP Extension" handling in RequestFactory --- src/Http/RequestFactory.php | 63 ++++++++++++++------ tests/Http/RequestFactory.proxy.phpt | 87 +++++++++++++++++----------- 2 files changed, 96 insertions(+), 54 deletions(-) diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index 993fa191..a240b7f9 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -194,30 +194,55 @@ public function createHttpRequest() $usingTrustedProxy = $remoteAddr && array_filter($this->proxies, function ($proxy) use ($remoteAddr) { return Helpers::ipMatch($remoteAddr, $proxy); }); - if ($usingTrustedProxy) { - if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { - $url->setScheme(strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0 ? 'https' : 'http'); - } + if(!empty($_SERVER['HTTP_FORWARDED'])) { + $forwardParams = preg_split('/[,]|[;]/', $_SERVER['HTTP_FORWARDED']); + foreach ($forwardParams as $forwardParam) { + $param = explode("=", $forwardParam); + $proxyParams[trim($param[0])][] = trim($param[1]); //e.g. array['for'][0] = 192.168.0.1 + } - if (!empty($_SERVER['HTTP_X_FORWARDED_PORT'])) { - $url->setPort((int) $_SERVER['HTTP_X_FORWARDED_PORT']); - } + if (isset($proxyParams['for'])) { + $remoteAddr = explode(':', $proxyParams['for'][0])[0]; + } + + if (isset($proxyParams['host']) && count($proxyParams['host']) === 1) { + echo $proxyParams['host'][0]; + $remoteHostArr = explode(':', $proxyParams['host'][0]); + if(count($remoteHostArr) === 2) { + $remoteHost = $remoteHostArr[0]; + $url->setPort((int) $remoteHostArr[1]); + } else { + $remoteHost = $proxyParams['host'][0]; + } + } + + $scheme = (isset($proxyParams['scheme']) && count($proxyParams['scheme']) === 1) ? $proxyParams['scheme'] : 'http'; + $url->setScheme(strcasecmp($scheme, 'https') === 0 ? 'https' : 'http'); + } else { + if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $url->setScheme(strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0 ? 'https' : 'http'); + } + + if (!empty($_SERVER['HTTP_X_FORWARDED_PORT'])) { + $url->setPort((int) $_SERVER['HTTP_X_FORWARDED_PORT']); + } - if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $xForwardedForWithoutProxies = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), function ($ip) { - return !array_filter($this->proxies, function ($proxy) use ($ip) { - return Helpers::ipMatch(trim($ip), $proxy); + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $xForwardedForWithoutProxies = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), function ($ip) { + return !array_filter($this->proxies, function ($proxy) use ($ip) { + return Helpers::ipMatch(trim($ip), $proxy); + }); }); - }); - $remoteAddr = trim(end($xForwardedForWithoutProxies)); - $xForwardedForRealIpKey = key($xForwardedForWithoutProxies); - } + $remoteAddr = trim(end($xForwardedForWithoutProxies)); + $xForwardedForRealIpKey = key($xForwardedForWithoutProxies); + } - if (isset($xForwardedForRealIpKey) && !empty($_SERVER['HTTP_X_FORWARDED_HOST'])) { - $xForwardedHost = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); - if (isset($xForwardedHost[$xForwardedForRealIpKey])) { - $remoteHost = trim($xForwardedHost[$xForwardedForRealIpKey]); + if (isset($xForwardedForRealIpKey) && !empty($_SERVER['HTTP_X_FORWARDED_HOST'])) { + $xForwardedHost = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); + if (isset($xForwardedHost[$xForwardedForRealIpKey])) { + $remoteHost = trim($xForwardedHost[$xForwardedForRealIpKey]); + } } } } diff --git a/tests/Http/RequestFactory.proxy.phpt b/tests/Http/RequestFactory.proxy.phpt index 297b2589..7f305527 100644 --- a/tests/Http/RequestFactory.proxy.phpt +++ b/tests/Http/RequestFactory.proxy.phpt @@ -11,38 +11,55 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -test(function () { - $_SERVER = [ - 'REMOTE_ADDR' => '127.0.0.3', - 'REMOTE_HOST' => 'localhost', - 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', - 'HTTP_X_FORWARDED_HOST' => 'otherhost', - ]; - - $factory = new RequestFactory; - $factory->setProxy('127.0.0.1'); - Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); - - $factory->setProxy('127.0.0.1/8'); - Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); -}); - -test(function () { - $_SERVER = [ - 'REMOTE_ADDR' => '10.0.0.2', //proxy2 - 'REMOTE_HOST' => 'proxy2', - 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', - 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', - ]; - - $factory = new RequestFactory; - $factory->setProxy('10.0.0.0/24'); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); - - $factory->setProxy(['10.0.0.1', '10.0.0.2']); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); -}); + test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', + 'HTTP_X_FORWARDED_HOST' => 'otherhost', + ]; + + $factory = new RequestFactory; + $factory->setProxy('127.0.0.1'); + Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); + + $factory->setProxy('127.0.0.1/8'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); + }); + + test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '10.0.0.2', //proxy2 + 'REMOTE_HOST' => 'proxy2', + 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', + 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', + ]; + + $factory = new RequestFactory; + $factory->setProxy('10.0.0.0/24'); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); + + $factory->setProxy(['10.0.0.1', '10.0.0.2']); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); + }); + + test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_FORWARDED' => 'for=23.75.45.200:85;host=otherhost', + ]; + + $factory = new RequestFactory; + $factory->setProxy('127.0.0.1'); + Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); + + $factory->setProxy('127.0.0.1/8'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); + }); From 61e927574373b078e7ec6c15d7fec000c92f3be2 Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 01:48:55 +0200 Subject: [PATCH 2/8] Implemented RFC 7239 - " Forwarded HTTP Extension" handling in RequestFactory --- tests/Http/RequestFactory.proxy.phpt | 88 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/Http/RequestFactory.proxy.phpt b/tests/Http/RequestFactory.proxy.phpt index 7f305527..02f8524a 100644 --- a/tests/Http/RequestFactory.proxy.phpt +++ b/tests/Http/RequestFactory.proxy.phpt @@ -11,55 +11,55 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; - test(function () { - $_SERVER = [ - 'REMOTE_ADDR' => '127.0.0.3', - 'REMOTE_HOST' => 'localhost', - 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', - 'HTTP_X_FORWARDED_HOST' => 'otherhost', - ]; +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', + 'HTTP_X_FORWARDED_HOST' => 'otherhost', + ]; - $factory = new RequestFactory; - $factory->setProxy('127.0.0.1'); - Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); + $factory = new RequestFactory; + $factory->setProxy('127.0.0.1'); + Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); - $factory->setProxy('127.0.0.1/8'); - Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); - }); + $factory->setProxy('127.0.0.1/8'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); +}); - test(function () { - $_SERVER = [ - 'REMOTE_ADDR' => '10.0.0.2', //proxy2 - 'REMOTE_HOST' => 'proxy2', - 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', - 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', - ]; +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '10.0.0.2', //proxy2 + 'REMOTE_HOST' => 'proxy2', + 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', + 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', + ]; - $factory = new RequestFactory; - $factory->setProxy('10.0.0.0/24'); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); + $factory = new RequestFactory; + $factory->setProxy('10.0.0.0/24'); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); - $factory->setProxy(['10.0.0.1', '10.0.0.2']); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); - }); + $factory->setProxy(['10.0.0.1', '10.0.0.2']); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); +}); - test(function () { - $_SERVER = [ - 'REMOTE_ADDR' => '127.0.0.3', - 'REMOTE_HOST' => 'localhost', - 'HTTP_FORWARDED' => 'for=23.75.45.200:85;host=otherhost', - ]; +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_FORWARDED' => 'for=23.75.45.200:85;host=otherhost', + ]; - $factory = new RequestFactory; - $factory->setProxy('127.0.0.1'); - Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); + $factory = new RequestFactory; + $factory->setProxy('127.0.0.1'); + Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); - $factory->setProxy('127.0.0.1/8'); - Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); - }); + $factory->setProxy('127.0.0.1/8'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); +}); From a6e205caa05a04f883f5df9c86c33523653bdbae Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 01:55:00 +0200 Subject: [PATCH 3/8] Deleted echo statement --- src/Http/RequestFactory.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index a240b7f9..527632b6 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -207,7 +207,6 @@ public function createHttpRequest() } if (isset($proxyParams['host']) && count($proxyParams['host']) === 1) { - echo $proxyParams['host'][0]; $remoteHostArr = explode(':', $proxyParams['host'][0]); if(count($remoteHostArr) === 2) { $remoteHost = $remoteHostArr[0]; From 44660bd94f424ce93a7f978d133d6e9cbb278f35 Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 05:29:13 +0200 Subject: [PATCH 4/8] case- insensitive handling of tokens --- src/Http/RequestFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index 527632b6..958dfcd6 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -199,7 +199,7 @@ public function createHttpRequest() $forwardParams = preg_split('/[,]|[;]/', $_SERVER['HTTP_FORWARDED']); foreach ($forwardParams as $forwardParam) { $param = explode("=", $forwardParam); - $proxyParams[trim($param[0])][] = trim($param[1]); //e.g. array['for'][0] = 192.168.0.1 + $proxyParams[strtolower(trim($param[0]))][] = trim($param[1]); //e.g. array['for'][0] = 192.168.0.1 } if (isset($proxyParams['for'])) { From 11461e62aff3ebfbbb66ea4889f3b5de0927fb08 Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 05:57:09 +0200 Subject: [PATCH 5/8] Proper handle of quoted strings. Will now work with IPv6. Added tests for port and scheme of the URL --- src/Http/RequestFactory.php | 30 +++++++++++++++-------- tests/Http/RequestFactory.proxy.phpt | 36 +++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index 958dfcd6..cbaa9c88 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -199,24 +199,34 @@ public function createHttpRequest() $forwardParams = preg_split('/[,]|[;]/', $_SERVER['HTTP_FORWARDED']); foreach ($forwardParams as $forwardParam) { $param = explode("=", $forwardParam); - $proxyParams[strtolower(trim($param[0]))][] = trim($param[1]); //e.g. array['for'][0] = 192.168.0.1 + $proxyParams[strtolower(trim($param[0]))][] = trim($param[1], "\"\t\n\r\0\x0B"); //e.g. array['for'][0] = 192.168.0.1 } - if (isset($proxyParams['for'])) { - $remoteAddr = explode(':', $proxyParams['for'][0])[0]; + if(isset($proxyParams['for'])) { + $address = $proxyParams['for'][0]; + if(strpos($address, '[') === FALSE) { //IPv4 + $remoteAddr = explode(':', $address)[0]; + } else { //IPv6 + $remoteAddr = substr($address, 1, strpos($address, ']')-1); + } } - if (isset($proxyParams['host']) && count($proxyParams['host']) === 1) { - $remoteHostArr = explode(':', $proxyParams['host'][0]); - if(count($remoteHostArr) === 2) { + if(isset($proxyParams['host']) && count($proxyParams['host']) === 1) { + $host = $proxyParams['host'][0]; + $startingDelimiterPosition = strpos($host, '['); + if($startingDelimiterPosition === FALSE) { //IPv4 + $remoteHostArr = explode(':', $host); $remoteHost = $remoteHostArr[0]; - $url->setPort((int) $remoteHostArr[1]); - } else { - $remoteHost = $proxyParams['host'][0]; + if(isset($remoteHostArr[1])) $url->setPort((int) $remoteHostArr[1]); + } else { //IPv6 + $endingDelimiterPosition = strpos($host, ']'); + $remoteHost = substr($host, strpos($host, '[')+1, $endingDelimiterPosition-1); + $remoteHostArr = explode(':', substr($host, $endingDelimiterPosition)); + if(isset($remoteHostArr[1])) $url->setPort((int) $remoteHostArr[1]); } } - $scheme = (isset($proxyParams['scheme']) && count($proxyParams['scheme']) === 1) ? $proxyParams['scheme'] : 'http'; + $scheme = (isset($proxyParams['scheme']) && count($proxyParams['scheme']) === 1) ? $proxyParams['scheme'][0] : 'http'; $url->setScheme(strcasecmp($scheme, 'https') === 0 ? 'https' : 'http'); } else { if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { diff --git a/tests/Http/RequestFactory.proxy.phpt b/tests/Http/RequestFactory.proxy.phpt index 02f8524a..543645e8 100644 --- a/tests/Http/RequestFactory.proxy.phpt +++ b/tests/Http/RequestFactory.proxy.phpt @@ -51,7 +51,7 @@ test(function () { $_SERVER = [ 'REMOTE_ADDR' => '127.0.0.3', 'REMOTE_HOST' => 'localhost', - 'HTTP_FORWARDED' => 'for=23.75.45.200:85;host=otherhost', + 'HTTP_FORWARDED' => 'For=23.75.45.200:85;HOST=otherhost', ]; $factory = new RequestFactory; @@ -63,3 +63,37 @@ test(function () { Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); }); + + +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]:47011";host=192.168.0.1:8080', + ]; + + $factory = new RequestFactory; + + $factory->setProxy('127.0.0.3'); + Assert::same('2001:db8:cafe::17', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('192.168.0.1', $factory->createHttpRequest()->getRemoteHost()); + + $url = $factory->createHttpRequest()->getUrl(); + Assert::same(8080, $url->getPort()); +}); + +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]";host=192.168.0.1;scheme=https', + ]; + + $factory = new RequestFactory; + + $factory->setProxy('127.0.0.3'); + Assert::same('2001:db8:cafe::17', $factory->createHttpRequest()->getRemoteAddress()); + + $url = $factory->createHttpRequest()->getUrl(); + Assert::same('https', $url->getScheme()); +}); From 17d339770d39bc58b498f5aca2aee28d89cec9e6 Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 06:24:45 +0200 Subject: [PATCH 6/8] Tests refactoring: - Split test into "x-forwarded" and "forwarded" files for proxy - Added tests for default scheme. - Added tests for every combination of IPv4/IPv6 with and without port for both "host" and "for" headers --- ...pt => RequestFactory.proxy.forwarded.phpt} | 55 +++++++++---------- .../RequestFactory.proxy.x-forwarded.phpt | 48 ++++++++++++++++ 2 files changed, 74 insertions(+), 29 deletions(-) rename tests/Http/{RequestFactory.proxy.phpt => RequestFactory.proxy.forwarded.phpt} (55%) create mode 100644 tests/Http/RequestFactory.proxy.x-forwarded.phpt diff --git a/tests/Http/RequestFactory.proxy.phpt b/tests/Http/RequestFactory.proxy.forwarded.phpt similarity index 55% rename from tests/Http/RequestFactory.proxy.phpt rename to tests/Http/RequestFactory.proxy.forwarded.phpt index 543645e8..71128e59 100644 --- a/tests/Http/RequestFactory.proxy.phpt +++ b/tests/Http/RequestFactory.proxy.forwarded.phpt @@ -1,7 +1,7 @@ '127.0.0.3', 'REMOTE_HOST' => 'localhost', - 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', - 'HTTP_X_FORWARDED_HOST' => 'otherhost', + 'HTTP_FORWARDED' => 'for=23.75.45.200;host=192.168.0.1', ]; $factory = new RequestFactory; @@ -26,74 +24,73 @@ test(function () { $factory->setProxy('127.0.0.1/8'); Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); + Assert::same('192.168.0.1', $factory->createHttpRequest()->getRemoteHost()); + + $url = $factory->createHttpRequest()->getUrl(); + Assert::same('http', $url->getScheme()); }); test(function () { $_SERVER = [ - 'REMOTE_ADDR' => '10.0.0.2', //proxy2 - 'REMOTE_HOST' => 'proxy2', - 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', - 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', + 'REMOTE_ADDR' => '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_FORWARDED' => 'for=23.75.45.200:8080;host=192.168.0.1:8080', ]; $factory = new RequestFactory; - $factory->setProxy('10.0.0.0/24'); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); - $factory->setProxy(['10.0.0.1', '10.0.0.2']); - Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); + $factory->setProxy('127.0.0.3'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('192.168.0.1', $factory->createHttpRequest()->getRemoteHost()); + + $url = $factory->createHttpRequest()->getUrl(); + Assert::same(8080, $url->getPort()); }); + test(function () { $_SERVER = [ 'REMOTE_ADDR' => '127.0.0.3', 'REMOTE_HOST' => 'localhost', - 'HTTP_FORWARDED' => 'For=23.75.45.200:85;HOST=otherhost', + 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]";host="[2001:db8:cafe::18]"', ]; $factory = new RequestFactory; - $factory->setProxy('127.0.0.1'); - Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); - $factory->setProxy('127.0.0.1/8'); - Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); + $factory->setProxy('127.0.0.3'); + Assert::same('2001:db8:cafe::17', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('2001:db8:cafe::18', $factory->createHttpRequest()->getRemoteHost()); }); - test(function () { $_SERVER = [ 'REMOTE_ADDR' => '127.0.0.3', 'REMOTE_HOST' => 'localhost', - 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]:47011";host=192.168.0.1:8080', + 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]:47831";host="[2001:db8:cafe::18]:47832"', ]; $factory = new RequestFactory; $factory->setProxy('127.0.0.3'); Assert::same('2001:db8:cafe::17', $factory->createHttpRequest()->getRemoteAddress()); - Assert::same('192.168.0.1', $factory->createHttpRequest()->getRemoteHost()); + Assert::same('2001:db8:cafe::18', $factory->createHttpRequest()->getRemoteHost()); $url = $factory->createHttpRequest()->getUrl(); - Assert::same(8080, $url->getPort()); + Assert::same(47832, $url->getPort()); }); + test(function () { $_SERVER = [ 'REMOTE_ADDR' => '127.0.0.3', 'REMOTE_HOST' => 'localhost', - 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]";host=192.168.0.1;scheme=https', + 'HTTP_FORWARDED' => 'for="[2001:db8:cafe::17]:47831" ; host="[2001:db8:cafe::18]:47832" ; scheme=https', ]; $factory = new RequestFactory; - $factory->setProxy('127.0.0.3'); - Assert::same('2001:db8:cafe::17', $factory->createHttpRequest()->getRemoteAddress()); $url = $factory->createHttpRequest()->getUrl(); Assert::same('https', $url->getScheme()); }); + diff --git a/tests/Http/RequestFactory.proxy.x-forwarded.phpt b/tests/Http/RequestFactory.proxy.x-forwarded.phpt new file mode 100644 index 00000000..31493588 --- /dev/null +++ b/tests/Http/RequestFactory.proxy.x-forwarded.phpt @@ -0,0 +1,48 @@ + '127.0.0.3', + 'REMOTE_HOST' => 'localhost', + 'HTTP_X_FORWARDED_FOR' => '23.75.45.200', + 'HTTP_X_FORWARDED_HOST' => 'otherhost', + ]; + + $factory = new RequestFactory; + $factory->setProxy('127.0.0.1'); + Assert::same('127.0.0.3', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('localhost', $factory->createHttpRequest()->getRemoteHost()); + + $factory->setProxy('127.0.0.1/8'); + Assert::same('23.75.45.200', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('otherhost', $factory->createHttpRequest()->getRemoteHost()); +}); + +test(function () { + $_SERVER = [ + 'REMOTE_ADDR' => '10.0.0.2', //proxy2 + 'REMOTE_HOST' => 'proxy2', + 'HTTP_X_FORWARDED_FOR' => '123.123.123.123, 172.16.0.1, 10.0.0.1', + 'HTTP_X_FORWARDED_HOST' => 'fake, real, proxy1', + ]; + + $factory = new RequestFactory; + $factory->setProxy('10.0.0.0/24'); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); + + $factory->setProxy(['10.0.0.1', '10.0.0.2']); + Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); + Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); +}); \ No newline at end of file From a2c7a79b08e61390e754b6734aeee63fd3a84da2 Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 10:14:14 +0200 Subject: [PATCH 7/8] Code simplifications --- src/Http/RequestFactory.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Http/RequestFactory.php b/src/Http/RequestFactory.php index cbaa9c88..b783c0f6 100644 --- a/src/Http/RequestFactory.php +++ b/src/Http/RequestFactory.php @@ -196,10 +196,10 @@ public function createHttpRequest() }); if ($usingTrustedProxy) { if(!empty($_SERVER['HTTP_FORWARDED'])) { - $forwardParams = preg_split('/[,]|[;]/', $_SERVER['HTTP_FORWARDED']); + $forwardParams = preg_split('/[,;]/', $_SERVER['HTTP_FORWARDED']); foreach ($forwardParams as $forwardParam) { - $param = explode("=", $forwardParam); - $proxyParams[strtolower(trim($param[0]))][] = trim($param[1], "\"\t\n\r\0\x0B"); //e.g. array['for'][0] = 192.168.0.1 + list($key, $value) = explode('=', $forwardParam, 2) + [1 => NULL]; + $proxyParams[strtolower(trim($key))][] = trim($value, " \t\""); } if(isset($proxyParams['for'])) { From 2383979f07e906284d48f955666b5a5a026f170a Mon Sep 17 00:00:00 2001 From: Patrick Kusebauch Date: Sun, 22 May 2016 10:42:06 +0200 Subject: [PATCH 8/8] Fixed coding standards for tests --- tests/Http/RequestFactory.proxy.forwarded.phpt | 1 - tests/Http/RequestFactory.proxy.x-forwarded.phpt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Http/RequestFactory.proxy.forwarded.phpt b/tests/Http/RequestFactory.proxy.forwarded.phpt index 71128e59..bffd0e61 100644 --- a/tests/Http/RequestFactory.proxy.forwarded.phpt +++ b/tests/Http/RequestFactory.proxy.forwarded.phpt @@ -93,4 +93,3 @@ test(function () { $url = $factory->createHttpRequest()->getUrl(); Assert::same('https', $url->getScheme()); }); - diff --git a/tests/Http/RequestFactory.proxy.x-forwarded.phpt b/tests/Http/RequestFactory.proxy.x-forwarded.phpt index 31493588..6bafaf70 100644 --- a/tests/Http/RequestFactory.proxy.x-forwarded.phpt +++ b/tests/Http/RequestFactory.proxy.x-forwarded.phpt @@ -45,4 +45,4 @@ test(function () { $factory->setProxy(['10.0.0.1', '10.0.0.2']); Assert::same('172.16.0.1', $factory->createHttpRequest()->getRemoteAddress()); Assert::same('real', $factory->createHttpRequest()->getRemoteHost()); -}); \ No newline at end of file +});