]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Add trusted IPs in config and try to ban forwarded IP on failed login
authorArthurHoaro <arthur@hoa.ro>
Wed, 3 Aug 2016 08:36:47 +0000 (10:36 +0200)
committerArthurHoaro <arthur@hoa.ro>
Sat, 5 Nov 2016 13:29:52 +0000 (14:29 +0100)
  * Add a new settings (which needs to be manually set): `security.trusted_proxies`
  * On login failure, if the `REMOTE_ADDR` is in the trusted proxies, try to retrieve the forwarded IP in headers.
  * If found, the client address is added in ipbans, else we do nothing.

Fixes #409

application/HttpUtils.php
index.php
tests/HttpUtils/GetIpAdressFromProxyTest.php [new file with mode: 0644]

index 27a39d3df223be0f457e8f3966a5b1bd7db7aefd..e705cfd6030cb0da7ff5e90bde930433bcecbbe0 100644 (file)
@@ -355,3 +355,29 @@ function page_url($server)
     }
     return index_url($server);
 }
+
+/**
+ * Retrieve the initial IP forwarded by the reverse proxy.
+ *
+ * Inspired from: https://github.com/zendframework/zend-http/blob/master/src/PhpEnvironment/RemoteAddress.php
+ *
+ * @param array $server     $_SERVER array which contains HTTP headers.
+ * @param array $trustedIps List of trusted IP from the configuration.
+ *
+ * @return string|bool The forwarded IP, or false if none could be extracted.
+ */
+function getIpAddressFromProxy($server, $trustedIps)
+{
+    $forwardedIpHeader = 'HTTP_X_FORWARDED_FOR';
+    if (empty($server[$forwardedIpHeader])) {
+        return false;
+    }
+
+    $ips = preg_split('/\s*,\s*/', $server[$forwardedIpHeader]);
+    $ips = array_diff($ips, $trustedIps);
+    if (empty($ips)) {
+        return false;
+    }
+
+    return array_pop($ips);
+}
index f9f248953eb1d09281b548a7c01e465f553bc31e..9f50d15323d2ea40207e14d08d030cfcdbb20025 100644 (file)
--- a/index.php
+++ b/index.php
@@ -332,8 +332,17 @@ include $conf->get('resource.ban_file', 'data/ipbans.php');
 function ban_loginFailed($conf)
 {
     $ip = $_SERVER['REMOTE_ADDR'];
+    $trusted = $conf->get('security.trusted_proxies', array());
+    if (in_array($ip, $trusted)) {
+        $ip = getIpAddressFromProxy($_SERVER, $trusted);
+        if (!$ip) {
+            return;
+        }
+    }
     $gb = $GLOBALS['IPBANS'];
-    if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0;
+    if (! isset($gb['FAILURES'][$ip])) {
+        $gb['FAILURES'][$ip]=0;
+    }
     $gb['FAILURES'][$ip]++;
     if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1))
     {
diff --git a/tests/HttpUtils/GetIpAdressFromProxyTest.php b/tests/HttpUtils/GetIpAdressFromProxyTest.php
new file mode 100644 (file)
index 0000000..6a74a45
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+
+require_once 'application/HttpUtils.php';
+
+/**
+ * Unitary tests for getIpAddressFromProxy()
+ */
+class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase {
+
+    /**
+     * Test without proxy
+     */
+    public function testWithoutProxy()
+    {
+        $this->assertFalse(getIpAddressFromProxy(array(), array()));
+    }
+
+    /**
+     * Test with a single IP in proxy header.
+     */
+    public function testWithOneForwardedIp()
+    {
+        $ip = '1.1.1.1';
+        $server = array('HTTP_X_FORWARDED_FOR' => $ip);
+        $this->assertEquals($ip, getIpAddressFromProxy($server, array()));
+    }
+
+    /**
+     * Test with a multiple IPs in proxy header.
+     */
+    public function testWithMultipleForwardedIp()
+    {
+        $ip = '1.1.1.1';
+        $ip2 = '2.2.2.2';
+
+        $server = array('HTTP_X_FORWARDED_FOR' => $ip .','. $ip2);
+        $this->assertEquals($ip2, getIpAddressFromProxy($server, array()));
+
+        $server = array('HTTP_X_FORWARDED_FOR' => $ip .' ,   '. $ip2);
+        $this->assertEquals($ip2, getIpAddressFromProxy($server, array()));
+    }
+
+    /**
+     * Test with a trusted IP address.
+     */
+    public function testWithTrustedIp()
+    {
+        $ip = '1.1.1.1';
+        $ip2 = '2.2.2.2';
+
+        $server = array('HTTP_X_FORWARDED_FOR' => $ip);
+        $this->assertFalse(getIpAddressFromProxy($server, array($ip)));
+
+        $server = array('HTTP_X_FORWARDED_FOR' => $ip .','. $ip2);
+        $this->assertEquals($ip2, getIpAddressFromProxy($server, array($ip)));
+        $this->assertFalse(getIpAddressFromProxy($server, array($ip, $ip2)));
+    }
+}