8000 feature #11379 Added new Forwarded header support for Request::getCli… · symfony/symfony@ac389b6 · GitHub
[go: up one dir, main page]

Skip to content

Commit ac389b6

Browse files
committed
feature #11379 Added new Forwarded header support for Request::getClientIps (tony-co)
This PR was submitted for the master branch but it was merged into the 2.7 branch instead (closes #11379). Discussion ---------- Added new Forwarded header support for Request::getClientIps | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #11073 | License | MIT | Doc PR | no Commits ------- 4c8a25a Added new Forwarded header support for Request::getClientIps
2 parents 51a8b11 + 4c8a25a commit ac389b6

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
*/
3131
class Request
3232
{
33+
const HEADER_FORWARDED = 'forwarded';
3334
const HEADER_CLIENT_IP = 'client_ip';
3435
const HEADER_CLIENT_HOST = 'client_host';
3536
const HEADER_CLIENT_PROTO = 'client_proto';
@@ -46,6 +47,9 @@ class Request
4647
const METHOD_TRACE = 'TRACE';
4748
const METHOD_CONNECT = 'CONNECT';
4849

50+
/**
51+
* @var string[]
52+
*/
4953
protected static $trustedProxies = array();
5054

5155
/**
@@ -62,10 +66,13 @@ class Request
6266
* Names for headers that can be trusted when
6367
* using trusted proxies.
6468
*
65-
* The default names are non-standard, but widely used
69+
* The FORWARDED header is the standard as of rfc7239.
70+
*
71+
* The other headers are non-standard, but widely used
6672
* by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
6773
*/
6874
protected static $trustedHeaders = array(
75+
self::HEADER_FORWARDED => 'FORWARDED',
6976
self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
7077
self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
7178
self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
@@ -823,24 +830,26 @@ public function setSession(SessionInterface $session)
823830
*/
824831
public function getClientIps()
825832
{
833+
$clientIps = array();
826834
$ip = $this->server->get('REMOTE_ADDR');
827835

828836
if (!self::$trustedProxies) {
829837
return array($ip);
830838
}
831839

832-
if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
833 8000 -
return array($ip);
840+
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
841+
$forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
842+
preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
843+
$clientIps = $matches[3];
844+
} elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
845+
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
834846
}
835847

836-
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
837848
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
838-
839849
$ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies
840850

841-
// Eliminate all IPs from the forwarded IP chain which are trusted proxies
842851
foreach ($clientIps as $key => $clientIp) {
843-
// Remove port on IPv4 address (unfortunately, it does happen)
852+
// Remove port (unfortunately, it does happen)
844853
if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
845854
$clientIps[$key] = $clientIp = $match[1];
846855
}

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,31 @@ public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $tru
875875
Request::setTrustedProxies(array());
876876
}
877877

878+
/**
879+
* @dataProvider testGetClientIpsForwardedProvider
880+
*/
881+
public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies)
882+
{
883+
$request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies);
884+
885+
$this->assertEquals($expected, $request->getClientIps());
886+
887+
Request::setTrustedProxies(array());
888+
}
889+
890+
public function testGetClientIpsForwardedProvider()
891+
{
892+
// $expected $remoteAddr $httpForwarded $trustedProxies
893+
return array(
894+
array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', null),
895+
array(array('_gazonk'), '127.0.0.1', 'for="_gazonk"', array('127.0.0.1')),
896+
array(array('88.88.88.88'), '127.0.0.1', 'for="88.88.88.88:80"', array('127.0.0.1')),
897+
array(array('192.0.2.60'), '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', array('::1')),
898+
array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', array('::1')),
899+
array(array('2001:db8:cafe::17'), '::1', 'for="[2001:db8:cafe::17]:4711', array('::1')),
900+
);
901+
}
902+
878903
public function testGetClientIpsProvider()
879904
{
880905
// $expected $remoteAddr $httpForwardedFor $trustedProxies
@@ -1467,6 +1492,25 @@ private function getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedF
14671492
return $request;
14681493
}
14691494

1495+
private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies)
1496+
{
1497+
$request = new Request();
1498+
1499+
$server = array('REMOTE_ADDR' => $remoteAddr);
1500+
1501+
if (null !== $httpForwarded) {
1502+
$server['HTTP_FORWARDED'] = $httpForwarded;
1503+
}
1504+
1505+
if ($trustedProxies) {
1506+
Request::setTrustedProxies($trustedProxies);
1507+
}
1508+
1509+
$request->initialize(array(), array(), array(), array(), array(), $server);
1510+
1511+
return $request;
1512+
}
1513+
14701514
public function testTrustedProxies()
14711515
{
14721516
$request = Request::create('http://example.com/');

0 commit comments

Comments
 (0)
0