diff --git a/library/Zend/Session/Validator/RemoteAddr.php b/library/Zend/Session/Validator/RemoteAddr.php index 8dd93033252..300ace61b6e 100644 --- a/library/Zend/Session/Validator/RemoteAddr.php +++ b/library/Zend/Session/Validator/RemoteAddr.php @@ -45,6 +45,13 @@ class RemoteAddr implements SessionValidator */ protected static $trustedProxies = array(); + /** + * HTTP header to introspect for proxies + * + * @var string + */ + protected static $proxyHeader = 'HTTP_X_FORWARDED_FOR'; + /** * Constructor * get the current user IP and store it in the session as 'valid data' @@ -103,6 +110,17 @@ public static function setTrustedProxies(array $trustedProxies) static::$trustedProxies = $trustedProxies; } + /** + * Set the header to introspect for proxy IPs + * + * @param string $header + * @return void + */ + public static function setProxyHeader($header = 'X-Forwarded-For') + { + static::$proxyHeader = static::normalizeProxyHeader($header); + } + /** * Returns client IP address. * @@ -134,13 +152,14 @@ protected function getIpAddressFromProxy() return false; } - // Only ever look at X-Forwarded-For header; Client-IP is unreliable - if (!isset($_SERVER['HTTP_X_FORWARDED_FOR']) || empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $header = static::$proxyHeader; + + if (!isset($_SERVER[$header]) || empty($_SERVER[$header])) { return false; } // Extract IPs - $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $ips = explode(',', $_SERVER[$header]); // trim, so we can compare against trusted proxies properly $ips = array_map('trim', $ips); // remove trusted proxy IPs @@ -175,4 +194,23 @@ public function getName() { return __CLASS__; } + + /** + * Normalize a header string + * + * Normalizes a header string to a format that is compatible with + * $_SERVER + * + * @param string $header + * @return string + */ + protected static function normalizeProxyHeader($header) + { + $header = strtoupper($header); + $header = str_replace('-', '_', $header); + if (0 !== strpos($header, 'HTTP_')) { + $header = 'HTTP_' . $header; + } + return $header; + } } diff --git a/tests/ZendTest/Session/Validator/RemoteAddrTest.php b/tests/ZendTest/Session/Validator/RemoteAddrTest.php index 449c6f237bd..fc8a8a3d7c9 100644 --- a/tests/ZendTest/Session/Validator/RemoteAddrTest.php +++ b/tests/ZendTest/Session/Validator/RemoteAddrTest.php @@ -32,6 +32,7 @@ protected function backup() ); RemoteAddr::setUseProxy(false); RemoteAddr::setTrustedProxies(array()); + RemoteAddr::setProxyHeader(); } protected function restore() @@ -39,6 +40,7 @@ protected function restore() $_SERVER = $this->backup; RemoteAddr::setUseProxy(false); RemoteAddr::setTrustedProxies(array()); + RemoteAddr::setProxyHeader(); } public function testGetData() @@ -115,7 +117,7 @@ public function testUsesRightMostAddressWhenMultipleHttpXForwardedForAddressesPr $this->restore(); } - public function testShouldNotUseClientIpHeaderToTestProxyCapabilities() + public function testShouldNotUseClientIpHeaderToTestProxyCapabilitiesByDefault() { $this->backup(); $_SERVER['REMOTE_ADDR'] = '0.1.2.3'; @@ -138,4 +140,17 @@ public function testWillOmitTrustedProxyIpsFromXForwardedForMatching() $this->assertEquals('2.1.2.3', $validator->getData()); $this->restore(); } + + public function testCanSpecifyWhichHeaderToUseStatically() + { + $this->backup(); + $_SERVER['REMOTE_ADDR'] = '0.1.2.3'; + $_SERVER['HTTP_X_FORWARDED_FOR'] = '2.1.2.3, 1.1.2.3'; + $_SERVER['HTTP_CLIENT_IP'] = '0.1.2.4'; + RemoteAddr::setUseProxy(true); + RemoteAddr::setProxyHeader('Client-Ip'); + $validator = new RemoteAddr(); + $this->assertEquals('0.1.2.4', $validator->getData()); + $this->restore(); + } }