Browse Source

fix clientIp method

Mohamed Elbahja 7 years ago
parent
commit
28f27f372f
2 changed files with 104 additions and 10 deletions
  1. 63 9
      src/Http/ServerRequest.php
  2. 41 1
      tests/TestCase/Http/ServerRequestTest.php

+ 63 - 9
src/Http/ServerRequest.php

@@ -126,6 +126,13 @@ class ServerRequest implements ArrayAccess, ServerRequestInterface
     public $trustProxy = false;
 
     /**
+     * trusted proxies list
+     * 
+     * @var array
+     */
+    protected $trustedProxies = [];
+
+    /**
      * Contents of php://input
      *
      * @var string
@@ -577,16 +584,63 @@ class ServerRequest implements ArrayAccess, ServerRequestInterface
      */
     public function clientIp()
     {
-        if ($this->trustProxy && $this->getEnv('HTTP_X_FORWARDED_FOR')) {
-            $addresses = explode(',', $this->getEnv('HTTP_X_FORWARDED_FOR'));
-            $ipaddr = end($addresses);
-        } elseif ($this->trustProxy && $this->getEnv('HTTP_CLIENT_IP')) {
-            $ipaddr = $this->getEnv('HTTP_CLIENT_IP');
-        } else {
-            $ipaddr = $this->getEnv('REMOTE_ADDR');
-        }
+        if ($this->trustProxy) {
+
+            if ($forwarded = $this->getEnv('HTTP_X_FORWARDED_FOR')) {
+
+                $addresses = array_map('trim', explode(',', $forwarded));
+                $trusted = (count($this->trustedProxies) > 0);
+                $n = count($addresses);
+
+                if ($trusted) {
+
+                    for ($i = 1; $i < $n; $i++)
+                    {
+                        if (in_array($addresses[$i], $this->trustedProxies) === false) {
+
+                            $trusted = false;
+                            break;
+                        }
+                    }
+                }
+
+                return (($trusted) ? $addresses[0] : $addresses[$n - 1]);
+
+            } else {
+
+                if ($ip = $this->getEnv('HTTP_X_REAL_IP')) {
+
+                    return $ip;
+                
+                } elseif ($ip = $this->getEnv('HTTP_CLIENT_IP')) {
 
-        return trim($ipaddr);
+                    return $ip;
+                }
+            }
+        }        
+
+        return $this->getEnv('REMOTE_ADDR');
+    }
+
+    /**
+     * register trusted proxies
+     *
+     * @param array $proxies ips list of trusted proxies
+     */
+    public function setTrustedProxies(array $proxies)
+    {
+        $this->trustedProxies = $proxies;
+        $this->trustProxy = true;
+    }
+
+    /**
+     * Get trusted proxies
+     *
+     * @return array
+     */
+    public function getTrustedProxies()
+    {
+        return $this->trustedProxies;
     }
 
     /**

+ 41 - 1
tests/TestCase/Http/ServerRequestTest.php

@@ -715,14 +715,18 @@ class ServerRequestTest extends TestCase
     {
         $request = new ServerRequest(['environment' => [
             'HTTP_X_FORWARDED_FOR' => '192.168.1.5, 10.0.1.1, proxy.com, real.ip',
+            'HTTP_X_REAL_IP' => '192.168.1.1',
             'HTTP_CLIENT_IP' => '192.168.1.2',
-            'REMOTE_ADDR' => '192.168.1.3'
+            'REMOTE_ADDR' => '192.168.1.3',
         ]]);
 
         $request->trustProxy = true;
         $this->assertEquals('real.ip', $request->clientIp());
 
         $request = $request->withEnv('HTTP_X_FORWARDED_FOR', '');
+        $this->assertEquals('192.168.1.1', $request->clientIp());
+
+        $request = $request->withEnv('HTTP_X_REAL_IP', '');
         $this->assertEquals('192.168.1.2', $request->clientIp());
 
         $request->trustProxy = false;
@@ -736,6 +740,42 @@ class ServerRequestTest extends TestCase
     }
 
     /**
+     * test clientIp method with trusted proxies
+     * 
+     * @return void
+     */
+    public function testClientIpWithTrustedProxies()
+    {
+        $request = new ServerRequest(['environment' => [
+            'HTTP_X_FORWARDED_FOR' => 'real.ip, 192.168.1.0, 192.168.1.2, 192.168.1.3',
+            'HTTP_X_REAL_IP' => '192.168.1.1',
+            'HTTP_CLIENT_IP' => '192.168.1.2',
+            'REMOTE_ADDR' => '192.168.1.4',
+        ]]);
+
+
+        $request->setTrustedProxies([
+            '192.168.1.0',
+            '192.168.1.1',
+            '192.168.1.2',
+            '192.168.1.3'
+        ]);
+
+        $this->assertEquals('real.ip', $request->clientIp());
+
+        $request = $request->withEnv('HTTP_X_FORWARDED_FOR', 
+            'spoof.fake.ip, real.ip, 192.168.1.0, 192.168.1.2, 192.168.1.3'
+        );
+        $this->assertEquals('192.168.1.3', $request->clientIp());
+
+        $request = $request->withEnv('HTTP_X_FORWARDED_FOR', '');
+        $this->assertEquals('192.168.1.1', $request->clientIp());
+
+        $request->trustProxy = false;
+        $this->assertEquals('192.168.1.4', $request->clientIp());
+    }
+
+    /**
      * Test the referrer function.
      *
      * @return void