diff options
author | ArthurHoaro <arthur@hoa.ro> | 2016-08-03 10:36:47 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2016-08-03 10:36:47 +0200 |
commit | 50d179183810a7b719bc10da2b9c4a95fd9dddee (patch) | |
tree | e669db360950025b4b6534075e940f532b0f00f3 | |
parent | c7a42ab1d9b21bf53cd30bc57b57789716c8711b (diff) | |
download | Shaarli-50d179183810a7b719bc10da2b9c4a95fd9dddee.tar.gz Shaarli-50d179183810a7b719bc10da2b9c4a95fd9dddee.tar.zst Shaarli-50d179183810a7b719bc10da2b9c4a95fd9dddee.zip |
Add trusted IPs in config and try to ban forwarded IP on failed login
* 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
-rw-r--r-- | application/HttpUtils.php | 26 | ||||
-rw-r--r-- | index.php | 11 | ||||
-rw-r--r-- | tests/HttpUtils/GetIpAdressFromProxyTest.php | 58 |
3 files changed, 94 insertions, 1 deletions
diff --git a/application/HttpUtils.php b/application/HttpUtils.php index 2e0792f9..354d261c 100644 --- a/application/HttpUtils.php +++ b/application/HttpUtils.php | |||
@@ -215,3 +215,29 @@ function page_url($server) | |||
215 | } | 215 | } |
216 | return index_url($server); | 216 | return index_url($server); |
217 | } | 217 | } |
218 | |||
219 | /** | ||
220 | * Retrieve the initial IP forwarded by the reverse proxy. | ||
221 | * | ||
222 | * Inspired from: https://github.com/zendframework/zend-http/blob/master/src/PhpEnvironment/RemoteAddress.php | ||
223 | * | ||
224 | * @param array $server $_SERVER array which contains HTTP headers. | ||
225 | * @param array $trustedIps List of trusted IP from the configuration. | ||
226 | * | ||
227 | * @return string|bool The forwarded IP, or false if none could be extracted. | ||
228 | */ | ||
229 | function getIpAddressFromProxy($server, $trustedIps) | ||
230 | { | ||
231 | $forwardedIpHeader = 'HTTP_X_FORWARDED_FOR'; | ||
232 | if (empty($server[$forwardedIpHeader])) { | ||
233 | return false; | ||
234 | } | ||
235 | |||
236 | $ips = preg_split('/\s*,\s*/', $server[$forwardedIpHeader]); | ||
237 | $ips = array_diff($ips, $trustedIps); | ||
238 | if (empty($ips)) { | ||
239 | return false; | ||
240 | } | ||
241 | |||
242 | return array_pop($ips); | ||
243 | } | ||
@@ -318,8 +318,17 @@ include $conf->get('resource.ban_file', 'data/ipbans.php'); | |||
318 | function ban_loginFailed($conf) | 318 | function ban_loginFailed($conf) |
319 | { | 319 | { |
320 | $ip = $_SERVER['REMOTE_ADDR']; | 320 | $ip = $_SERVER['REMOTE_ADDR']; |
321 | $trusted = $conf->get('security.trusted_proxies', array()); | ||
322 | if (in_array($ip, $trusted)) { | ||
323 | $ip = getIpAddressFromProxy($_SERVER, $trusted); | ||
324 | if (!$ip) { | ||
325 | return; | ||
326 | } | ||
327 | } | ||
321 | $gb = $GLOBALS['IPBANS']; | 328 | $gb = $GLOBALS['IPBANS']; |
322 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; | 329 | if (! isset($gb['FAILURES'][$ip])) { |
330 | $gb['FAILURES'][$ip]=0; | ||
331 | } | ||
323 | $gb['FAILURES'][$ip]++; | 332 | $gb['FAILURES'][$ip]++; |
324 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) | 333 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) |
325 | { | 334 | { |
diff --git a/tests/HttpUtils/GetIpAdressFromProxyTest.php b/tests/HttpUtils/GetIpAdressFromProxyTest.php new file mode 100644 index 00000000..6a74a45a --- /dev/null +++ b/tests/HttpUtils/GetIpAdressFromProxyTest.php | |||
@@ -0,0 +1,58 @@ | |||
1 | <?php | ||
2 | |||
3 | require_once 'application/HttpUtils.php'; | ||
4 | |||
5 | /** | ||
6 | * Unitary tests for getIpAddressFromProxy() | ||
7 | */ | ||
8 | class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase { | ||
9 | |||
10 | /** | ||
11 | * Test without proxy | ||
12 | */ | ||
13 | public function testWithoutProxy() | ||
14 | { | ||
15 | $this->assertFalse(getIpAddressFromProxy(array(), array())); | ||
16 | } | ||
17 | |||
18 | /** | ||
19 | * Test with a single IP in proxy header. | ||
20 | */ | ||
21 | public function testWithOneForwardedIp() | ||
22 | { | ||
23 | $ip = '1.1.1.1'; | ||
24 | $server = array('HTTP_X_FORWARDED_FOR' => $ip); | ||
25 | $this->assertEquals($ip, getIpAddressFromProxy($server, array())); | ||
26 | } | ||
27 | |||
28 | /** | ||
29 | * Test with a multiple IPs in proxy header. | ||
30 | */ | ||
31 | public function testWithMultipleForwardedIp() | ||
32 | { | ||
33 | $ip = '1.1.1.1'; | ||
34 | $ip2 = '2.2.2.2'; | ||
35 | |||
36 | $server = array('HTTP_X_FORWARDED_FOR' => $ip .','. $ip2); | ||
37 | $this->assertEquals($ip2, getIpAddressFromProxy($server, array())); | ||
38 | |||
39 | $server = array('HTTP_X_FORWARDED_FOR' => $ip .' , '. $ip2); | ||
40 | $this->assertEquals($ip2, getIpAddressFromProxy($server, array())); | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Test with a trusted IP address. | ||
45 | */ | ||
46 | public function testWithTrustedIp() | ||
47 | { | ||
48 | $ip = '1.1.1.1'; | ||
49 | $ip2 = '2.2.2.2'; | ||
50 | |||
51 | $server = array('HTTP_X_FORWARDED_FOR' => $ip); | ||
52 | $this->assertFalse(getIpAddressFromProxy($server, array($ip))); | ||
53 | |||
54 | $server = array('HTTP_X_FORWARDED_FOR' => $ip .','. $ip2); | ||
55 | $this->assertEquals($ip2, getIpAddressFromProxy($server, array($ip))); | ||
56 | $this->assertFalse(getIpAddressFromProxy($server, array($ip, $ip2))); | ||
57 | } | ||
58 | } | ||