diff options
author | Lukas Reschke <lukas@statuscode.ch> | 2017-04-12 20:32:48 +0200 |
---|---|---|
committer | Lukas Reschke <lukas@statuscode.ch> | 2017-04-13 12:00:16 +0200 |
commit | 66835476b59b8be7593d4cfa03a51c4f265d7e26 (patch) | |
tree | 91770c8fe403da25af50e6336727ab55fe57cd27 /lib/private/Security/Bruteforce | |
parent | 5505faa3d7b6f5a95f18fe5027355d700d69f396 (diff) | |
download | nextcloud-server-66835476b59b8be7593d4cfa03a51c4f265d7e26.tar.gz nextcloud-server-66835476b59b8be7593d4cfa03a51c4f265d7e26.zip |
Add support for ratelimiting via annotations
This allows adding rate limiting via annotations to controllers, as one example:
```
@UserRateThrottle(limit=5, period=100)
@AnonRateThrottle(limit=1, period=100)
```
Would mean that logged-in users can access the page 5 times within 100 seconds, and anonymous users 1 time within 100 seconds. If only an AnonRateThrottle is specified that one will also be applied to logged-in users.
Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
Diffstat (limited to 'lib/private/Security/Bruteforce')
-rw-r--r-- | lib/private/Security/Bruteforce/Throttler.php | 72 |
1 files changed, 7 insertions, 65 deletions
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php index 73a27b677b0..b2524b63c63 100644 --- a/lib/private/Security/Bruteforce/Throttler.php +++ b/lib/private/Security/Bruteforce/Throttler.php @@ -23,6 +23,7 @@ namespace OC\Security\Bruteforce; +use OC\Security\Normalizer\IpAddress; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\IDBConnection; @@ -83,67 +84,6 @@ class Throttler { } /** - * Return the given subnet for an IPv4 address and mask bits - * - * @param string $ip - * @param int $maskBits - * @return string - */ - private function getIPv4Subnet($ip, - $maskBits = 32) { - $binary = \inet_pton($ip); - for ($i = 32; $i > $maskBits; $i -= 8) { - $j = \intdiv($i, 8) - 1; - $k = (int) \min(8, $i - $maskBits); - $mask = (0xff - ((pow(2, $k)) - 1)); - $int = \unpack('C', $binary[$j]); - $binary[$j] = \pack('C', $int[1] & $mask); - } - return \inet_ntop($binary).'/'.$maskBits; - } - - /** - * Return the given subnet for an IPv6 address and mask bits - * - * @param string $ip - * @param int $maskBits - * @return string - */ - private function getIPv6Subnet($ip, $maskBits = 48) { - $binary = \inet_pton($ip); - for ($i = 128; $i > $maskBits; $i -= 8) { - $j = \intdiv($i, 8) - 1; - $k = (int) \min(8, $i - $maskBits); - $mask = (0xff - ((pow(2, $k)) - 1)); - $int = \unpack('C', $binary[$j]); - $binary[$j] = \pack('C', $int[1] & $mask); - } - return \inet_ntop($binary).'/'.$maskBits; - } - - /** - * Return the given subnet for an IP and the configured mask bits - * - * Determine if the IP is an IPv4 or IPv6 address, then pass to the correct - * method for handling that specific type. - * - * @param string $ip - * @return string - */ - private function getSubnet($ip) { - if (\preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $ip)) { - return $this->getIPv4Subnet( - $ip, - 32 - ); - } - return $this->getIPv6Subnet( - $ip, - 128 - ); - } - - /** * Register a failed attempt to bruteforce a security control * * @param string $action @@ -158,11 +98,12 @@ class Throttler { return; } + $ipAddress = new IpAddress($ip); $values = [ 'action' => $action, 'occurred' => $this->timeFactory->getTime(), - 'ip' => $ip, - 'subnet' => $this->getSubnet($ip), + 'ip' => (string)$ipAddress, + 'subnet' => $ipAddress->getSubnet(), 'metadata' => json_encode($metadata), ]; @@ -254,7 +195,8 @@ class Throttler { * @return int */ public function getDelay($ip, $action = '') { - if ($this->isIPWhitelisted($ip)) { + $ipAddress = new IpAddress($ip); + if ($this->isIPWhitelisted((string)$ipAddress)) { return 0; } @@ -266,7 +208,7 @@ class Throttler { $qb->select('*') ->from('bruteforce_attempts') ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime))) - ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($this->getSubnet($ip)))); + ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet()))); if ($action !== '') { $qb->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action))); |