fixed algorithm used to determine the trusted client IP
This commit is contained in:
parent
254b11062e
commit
b45873a3f6
@ -20,7 +20,9 @@ namespace Symfony\Component\HttpFoundation;
|
|||||||
*/
|
*/
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
protected static $trustProxy = false;
|
protected static $trustProxyData = false;
|
||||||
|
|
||||||
|
protected static $trustedProxies = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Symfony\Component\HttpFoundation\ParameterBag
|
* @var \Symfony\Component\HttpFoundation\ParameterBag
|
||||||
@ -357,14 +359,26 @@ class Request
|
|||||||
/**
|
/**
|
||||||
* Trusts $_SERVER entries coming from proxies.
|
* Trusts $_SERVER entries coming from proxies.
|
||||||
*
|
*
|
||||||
* You should only call this method if your application
|
* @deprecated Deprecated since version 2.0, to be removed in 2.3. Use setTrustedProxies instead.
|
||||||
* is hosted behind a reverse proxy that you manage.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
*/
|
||||||
public static function trustProxyData()
|
public static function trustProxyData()
|
||||||
{
|
{
|
||||||
self::$trustProxy = true;
|
self::$trustProxyData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a list of trusted proxies.
|
||||||
|
*
|
||||||
|
* You should only list the reverse proxies that you manage directly.
|
||||||
|
*
|
||||||
|
* @param array $proxies A list of trusted proxies
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
public static function setTrustedProxies(array $proxies)
|
||||||
|
{
|
||||||
|
self::$trustedProxies = $proxies;
|
||||||
|
self::$trustProxyData = $proxies ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,23 +455,41 @@ class Request
|
|||||||
/**
|
/**
|
||||||
* Returns the client IP address.
|
* Returns the client IP address.
|
||||||
*
|
*
|
||||||
* @param Boolean $proxy Whether the current request has been made behind a proxy or not
|
* This method can read the client IP address from the "X-Forwarded-For" header
|
||||||
|
* when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
|
||||||
|
* header value is a comma+space separated list of IP addresses, the left-most
|
||||||
|
* being the original client, and each successive proxy that passed the request
|
||||||
|
* adding the IP address where it received the request from.
|
||||||
|
*
|
||||||
|
* @param Boolean $proxy Whether the current request has been made behind a proxy or not (deprecated)
|
||||||
*
|
*
|
||||||
* @return string The client IP address
|
* @return string The client IP address
|
||||||
*
|
*
|
||||||
|
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
|
||||||
|
*
|
||||||
|
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function getClientIp($proxy = false)
|
public function getClientIp($proxy = false)
|
||||||
{
|
{
|
||||||
if ($proxy) {
|
$ip = $this->server->get('REMOTE_ADDR');
|
||||||
if (self::$trustProxy && $this->server->has('HTTP_X_FORWARDED_FOR')) {
|
|
||||||
$clientIp = explode(',', $this->server->get('HTTP_X_FORWARDED_FOR'), 2);
|
|
||||||
|
|
||||||
return isset($clientIp[0]) ? trim($clientIp[0]) : '';
|
if (!$proxy && !self::$trustProxyData) {
|
||||||
}
|
return $ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->server->get('REMOTE_ADDR');
|
if (!$this->server->has('HTTP_X_FORWARDED_FOR')) {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientIps = array_map('trim', explode(',', $this->server->get('HTTP_X_FORWARDED_FOR')));
|
||||||
|
$clientIps[] = $ip;
|
||||||
|
|
||||||
|
$trustedProxies = ($proxy || self::$trustProxyData) && !self::$trustedProxies ? array($ip) : self::$trustedProxies;
|
||||||
|
$clientIps = array_diff($clientIps, $trustedProxies);
|
||||||
|
|
||||||
|
return array_pop($clientIps);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -560,7 +592,7 @@ class Request
|
|||||||
*/
|
*/
|
||||||
public function getPort()
|
public function getPort()
|
||||||
{
|
{
|
||||||
if (self::$trustProxy && $this->headers->has('X-Forwarded-Port')) {
|
if (self::$trustProxyData && $this->headers->has('X-Forwarded-Port')) {
|
||||||
return $this->headers->get('X-Forwarded-Port');
|
return $this->headers->get('X-Forwarded-Port');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,9 +715,9 @@ class Request
|
|||||||
return (
|
return (
|
||||||
(strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
|
(strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
|
||||||
||
|
||
|
||||||
(self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
|
(self::$trustProxyData && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
|
||||||
||
|
||
|
||||||
(self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
|
(self::$trustProxyData && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +730,7 @@ class Request
|
|||||||
*/
|
*/
|
||||||
public function getHost()
|
public function getHost()
|
||||||
{
|
{
|
||||||
if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
|
if (self::$trustProxyData && $host = $this->headers->get('X_FORWARDED_HOST')) {
|
||||||
$elements = explode(',', $host);
|
$elements = explode(',', $host);
|
||||||
|
|
||||||
$host = trim($elements[count($elements) - 1]);
|
$host = trim($elements[count($elements) - 1]);
|
||||||
|
@ -19,11 +19,6 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
|
|
||||||
class RequestTest extends \PHPUnit_Framework_TestCase
|
class RequestTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
Request::trustProxyData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers Symfony\Component\HttpFoundation\Request::__construct
|
* @covers Symfony\Component\HttpFoundation\Request::__construct
|
||||||
*/
|
*/
|
||||||
@ -430,15 +425,17 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
|||||||
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com'));
|
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com'));
|
||||||
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header');
|
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header');
|
||||||
|
|
||||||
// Host header with port number.
|
// Host header with port number
|
||||||
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com:8080'));
|
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_HOST' => 'www.exemple.com:8080'));
|
||||||
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header with port number');
|
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from Host Header with port number');
|
||||||
|
|
||||||
// Server values.
|
// Server values
|
||||||
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com'));
|
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com'));
|
||||||
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from server name');
|
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from server name');
|
||||||
|
|
||||||
// X_FORWARDED_HOST.
|
Request::setTrustedProxies(array('1.1.1.1'));
|
||||||
|
|
||||||
|
// X_FORWARDED_HOST
|
||||||
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_X_FORWARDED_HOST' => 'www.exemple.com'));
|
$request->initialize(array(), array(), array(), array(), array(), array('HTTP_X_FORWARDED_HOST' => 'www.exemple.com'));
|
||||||
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from X_FORWARDED_HOST');
|
$this->assertEquals('www.exemple.com', $request->getHost(), '->getHost() from X_FORWARDED_HOST');
|
||||||
|
|
||||||
@ -458,6 +455,8 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com', 'HTTP_HOST' => 'www.host.com'));
|
$request->initialize(array(), array(), array(), array(), array(), array('SERVER_NAME' => 'www.exemple.com', 'HTTP_HOST' => 'www.host.com'));
|
||||||
$this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME ');
|
$this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME ');
|
||||||
|
|
||||||
|
Request::setTrustedProxies(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -496,17 +495,19 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider testGetClientIpProvider
|
* @dataProvider testGetClientIpProvider
|
||||||
*/
|
*/
|
||||||
public function testGetClientIp($expected, $proxy, $remoteAddr, $httpForwardedFor)
|
public function testGetClientIp($expected, $proxy, $remoteAddr, $httpForwardedFor, $trustedProxies)
|
||||||
{
|
{
|
||||||
$request = new Request;
|
$request = new Request();
|
||||||
$this->assertEquals('', $request->getClientIp());
|
|
||||||
$this->assertEquals('', $request->getClientIp(true));
|
|
||||||
|
|
||||||
$server = array('REMOTE_ADDR' => $remoteAddr);
|
$server = array('REMOTE_ADDR' => $remoteAddr);
|
||||||
if (null !== $httpForwardedFor) {
|
if (null !== $httpForwardedFor) {
|
||||||
$server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
|
$server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($proxy || $trustedProxies) {
|
||||||
|
Request::setTrustedProxies(null === $trustedProxies ? array($remoteAddr) : $trustedProxies);
|
||||||
|
}
|
||||||
|
|
||||||
$request->initialize(array(), array(), array(), array(), array(), $server);
|
$request->initialize(array(), array(), array(), array(), array(), $server);
|
||||||
$this->assertEquals($expected, $request->getClientIp($proxy));
|
$this->assertEquals($expected, $request->getClientIp($proxy));
|
||||||
}
|
}
|
||||||
@ -514,13 +515,15 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testGetClientIpProvider()
|
public function testGetClientIpProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('88.88.88.88', false, '88.88.88.88', null),
|
array('88.88.88.88', false, '88.88.88.88', null, null),
|
||||||
array('127.0.0.1', false, '127.0.0.1', null),
|
array('127.0.0.1', false, '127.0.0.1', null, null),
|
||||||
array('127.0.0.1', false, '127.0.0.1', '88.88.88.88'),
|
array('::1', false, '::1', null, null),
|
||||||
array('88.88.88.88', true, '127.0.0.1', '88.88.88.88'),
|
array('127.0.0.1', false, '127.0.0.1', '88.88.88.88', null),
|
||||||
array('::1', false, '::1', null),
|
array('88.88.88.88', true, '127.0.0.1', '88.88.88.88', null),
|
||||||
array('2620:0:1cfe:face:b00c::3', true, '::1', '2620:0:1cfe:face:b00c::3, ::1'),
|
array('2620:0:1cfe:face:b00c::3', true, '::1', '2620:0:1cfe:face:b00c::3', null),
|
||||||
array('88.88.88.88', true, '123.45.67.89', '88.88.88.88, 87.65.43.21, 127.0.0.1'),
|
array('88.88.88.88', true, '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', null),
|
||||||
|
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')),
|
||||||
|
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')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user