From 817b83687028894574ba5a8e8ee8f3af21f23188 Mon Sep 17 00:00:00 2001 From: Daniel Hensby Date: Tue, 1 Mar 2016 12:56:34 +0000 Subject: [PATCH] FIX getIP from behind a load-balancer that adds many IPs to the header --- control/HTTPRequest.php | 26 ++++++++++++++++++++++++-- tests/control/HTTPRequestTest.php | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/control/HTTPRequest.php b/control/HTTPRequest.php index 21e5db00e..47d2ce9ff 100644 --- a/control/HTTPRequest.php +++ b/control/HTTPRequest.php @@ -669,14 +669,36 @@ class SS_HTTPRequest implements ArrayAccess { } if ($headerOverrideIP) { - return $headerOverrideIP; + return $this->getIPFromHeaderValue($headerOverrideIP); } elseif(isset($_SERVER['REMOTE_ADDR'])) { return $_SERVER['REMOTE_ADDR']; } else { return null; } } - + + /** + * Extract an IP address from a header value that has been obtained. Accepts single IP or comma separated string of + * IPs + * + * @param string $headerValue The value from a trusted header + * @return string The IP address + */ + protected function getIPFromHeaderValue($headerValue) { + if (strpos($headerValue, ',') !== false) { + //sometimes the IP from a load balancer could be "x.x.x.x, y.y.y.y, z.z.z.z" so we need to find the most + // likely candidate + $ips = explode(',', $headerValue); + foreach ($ips as $ip) { + $ip = trim($ip); + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) { + return $ip; + } + } + } + return $headerValue; + } + /** * Returns all mimetypes from the HTTP "Accept" header * as an array. diff --git a/tests/control/HTTPRequestTest.php b/tests/control/HTTPRequestTest.php index 734731c10..09ee883b8 100644 --- a/tests/control/HTTPRequestTest.php +++ b/tests/control/HTTPRequestTest.php @@ -254,4 +254,23 @@ class HTTPRequestTest extends SapphireTest { $this->assertEquals('home?test=1', $req->getURL(true)); $this->assertEquals('home', $req->getURL()); } + + public function testGetIPFromHeaderValue() { + $req = new SS_HTTPRequest('GET', '/'); + $reflectionMethod = new ReflectionMethod($req, 'getIPFromHeaderValue'); + $reflectionMethod->setAccessible(true); + + $headers = array( + '80.79.208.21, 149.126.76.1, 10.51.0.68' => '80.79.208.21', + '52.19.19.103, 10.51.0.49' => '52.19.19.103', + '10.51.0.49, 52.19.19.103' => '52.19.19.103', + '10.51.0.49' => '10.51.0.49', + '127.0.0.1, 10.51.0.49' => '127.0.0.1', + ); + + foreach ($headers as $header => $ip) { + $this->assertEquals($ip, $reflectionMethod->invoke($req, $header)); + } + + } }