diff --git a/application/HttpUtils.php b/application/HttpUtils.php index 2e0792f..354d261 100644 --- a/application/HttpUtils.php +++ b/application/HttpUtils.php @@ -215,3 +215,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); +} diff --git a/index.php b/index.php index 55b12ad..ab51fa2 100644 --- a/index.php +++ b/index.php @@ -318,8 +318,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 index 0000000..6a74a45 --- /dev/null +++ b/tests/HttpUtils/GetIpAdressFromProxyTest.php @@ -0,0 +1,58 @@ +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))); + } +}