8000 fixed algorithm used to determine the trusted client IP · symfony/symfony@b45873a · GitHub
[go: up one dir, main page]

Skip to content

Commit b45873a

Browse files
committed
fixed algorithm used to determine the trusted client IP
1 parent 254b110 commit b45873a

File tree

2 files changed

+70
-35
lines changed

2 files changed

+70
-35
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
*/
2121
class Request
2222
{
23-
protected static $trustProxy = false;
23+
protected static $trustProxyData = false;
24+
25+
protected static $trustedProxies = array();
2426

2527
/**
2628
* @var \Symfony\Component\HttpFoundation\ParameterBag
@@ -357,14 +359,26 @@ public function overrideGlobals()
357359
/**
358360
* Trusts $_SERVER entries coming from proxies.
359361
*
360-
* You should only call this method if your application
361-
* is hosted behind a reverse proxy that you manage.
362+
* @deprecated Deprecated since version 2.0, to be removed in 2.3. Use setTrustedProxies instead.
363+
*/
364+
public static function trustProxyData()
365+
{
366+
self::$trustProxyData = true;
367+
}
368+
369+
/**
370+
* Sets a list of trusted proxies.
371+
*
372+
* You should only list the reverse proxies that you manage directly.
373+
*
374+
* @param array $proxies A list of trusted proxies
362375
*
363376
* @api
364377
*/
365-
public static function trustProxyData()
378+
public static function setTrustedProxies(array $proxies)
366379
{
367-
self::$trustProxy = true;
380+
self::$trustedProxies = $proxies;
381+
self::$trustProxyData = $proxies ? true : false;
368382
}
369383

370384
/**
@@ -441,23 +455,41 @@ public function setSession(Session $session)
441455
/**
442456
* Returns the client IP address.
443457
*
444-
* @param Boolean $proxy Whether the current request has been made behind a proxy or not
458+
* This method can read the client IP address from the "X-Forwarded-For" header
459+
* when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
460+
* header value is a comma+space separated list of IP addresses, the left-most
461+
* being the original client, and each successive proxy that passed the request
462+
* adding the IP address where it received the request from.
463+
*
464+
* @param Boolean $proxy Whether the current request has been made behind a proxy or not (deprecated)
445465
*
446466
* @return string The client IP address
447467
*
468+
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
469+
*
470+
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
471+
*
448472
* @api
449473
*/
450474
public function getClientIp($proxy = false)
451475
{
452-
if ($proxy) {
453-
if (self::$trustProxy && $this->server->has('HTTP_X_FORWARDED_FOR')) {
454-
$clientIp = explode(',', $this->server->get('HTTP_X_FORWARDED_FOR'), 2);
476+
$ip = $this->server->get('REMOTE_ADDR');
455477

456-
return isset($clientIp[0]) ? trim($clientIp[0]) : '';
457-
}
478+
if (!$proxy && !self::$trustProxyData) {
479+
return $ip;
458480
}
459481

460-
return $this->server->get('REMOTE_ADDR');
482+
if (!$this->server->has('HTTP_X_FORWARDED_FOR')) {
483+
return $ip;
484+
}
485+
486+
$clientIps = array_map('trim', explode(',', $this->server->get('HTTP_X_FORWARDED_FOR')));
487+
$clientIps[] = $ip;
488+
489+
$trustedProxies = ($proxy || self::$trustProxyData) && !self::$trustedProxies ? array($ip) : self::$trustedProxies;
490+
$clientIps = array_diff($clientIps, $trustedProxies);
491+
492+
return array_pop($clientIps);
461493
}
462494

463495
/**
@@ -560,7 +592,7 @@ public function getScheme()
560592
*/
561593
public function getPort()
562594
{
563-
if (self::$trustProxy && $this->headers->has('X-Forwarded-Port')) {
595+
if (self::$trustProxyData && $this->headers->has('X-Forwarded-Port')) {
564596
return $this->headers->get('X-Forwarded-Port');
565597
}
566598

@@ -683,9 +715,9 @@ public function isSecure()
683715
return (
684716
(strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
685717
||
686-
(self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
718+
(self::$trustProxyData && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
687719
||
688-
(self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
720+
(self::$trustProxyData && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
689721
);
690722
}
691723

@@ -698,7 +730,7 @@ public function isSecure()
698730
*/
699731
public function getHost()
700732
{
701-
if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
733+
if (self::$trustProxyData && $host = $this->headers->get('X_FORWARDED_HOST')) {
702734
$elements = explode(',', $host);
703735

704736
$host = trim($elements[count($elements) - 1]);

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@
1919

2020
class RequestTest extends \PHPUnit_Framework_TestCase
2121
{
22-
public function setUp()
23-
{
24-
Request::trustProxyData();
25-
}
26-
2722
/**
2823
* @covers Symfony\Component\HttpFoundation\Request::__construct
2924
*/
@@ -430,15 +425,17 @@ public function testGetHost()
430425
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com'));
431426
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header');
432427

433-
// Host header with port number.
428+
// Host header with port number
434429
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com:8080'));
435430
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header with port number');
436431

437-
// Server values.
432+
// Server values
438433
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com'));
439434
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from server name');
440435

441-
// X_FORWARDED_HOST.
436+
Request::setTrustedProxies(array('1.1.1.1'));
437+
438+
// X_FORWARDED_HOST
442439
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_X_FORWARDED_HOST' => 'www.exemple.com'));
443440
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from X_FORWARDED_HOST');
444441

@@ -458,6 +455,8 @@ public function testGetHost()
458455

459456
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com', 'HTTP_HOST' => 'www.host.com'));
460457
$this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME ');
458+
459+
Request::setTrustedProxies(array());
461460
}
462461

463462
/**
@@ -496,31 +495,35 @@ public function testGetSetMethod()
496495
/**
497496
* @dataProvider testGetClientIpProvider
498497
*/
499-
public function testGetClientIp($expected, $proxy, $remoteAddr, $httpForwardedFor)
498+
public function testGetClientIp($expected, $proxy, $remoteAddr, $httpForwardedFor, $trustedProxies)
500499
{
501-
$request = new Request;
502-
$this->assertEquals('', $request->getClientIp());
503-
$this->assertEquals('', $request->getClientIp(true));
500+
$request = new Request();
504501

505502
$server = array('REMOTE_ADDR' => $remoteAddr);
506503
if (null !== $httpForwardedFor) {
507504
$server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
508505
}
509506

507+
if ($proxy || $trustedProxies) {
508+
Request::setTrustedProxies(null === $trustedProxies ? array($remoteAddr) : $trustedProxies);
509+
}
510+
510511
$request->initialize(array(), array(), array(), array(), array(), $server);
511512
$this->assertEquals($expected, $request->getClientIp($proxy));
512513
}
513514

514515
public function testGetClientIpProvider()
515516
{
516517
return array(
517-
array('88.88.88.88', false, '88.88.88.88', null),
518-
array('127.0.0.1', false, '127.0.0.1', null),
519-
array('127.0.0.1', false, '127.0.0.1', '88.88.88.88'),
520-
array('88.88.88.88', true, '127.0.0.1', '88.88.88.88'),
521-
array('::1', false, '::1', null),
522-
array('2620:0:1cfe:face:b00c::3', true, '::1', '2620:0:1cfe:face:b00c::3, ::1'),
523-
array('88.88.88.88', true, '123.45.67.89', '88.88.88.88, 87.65.43.21, 127.0.0.1'),
518+
array('88.88.88.88', false, '88.88.88.88', null, null),
519+
array('127.0.0.1', false, '127.0.0.1', null, null),
520+
array('::1', false, '::1', null, null),
521+
array('127.0.0.1', false, '127.0.0.1', '88.88.88.88', null),
522+
array('88.88.88.88', true, '127.0.0.1', '88.88.88.88', null),
523+
array('2620:0:1cfe:face:b00c::3', true, '::1', '2620:0:1cfe:face:b00c::3', null),
524+
array('88.88.88.88', true, '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', null),
525+
array('87.65.43.21', true, '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '88.88.88.88')),
526+
array('87.65.43.21', false, '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', array('123.45.67.89', '88.88.88.88')),
524527
);
525528
}
526529

0 commit comments

Comments
 (0)
0