From 5a270c271567d3c6ef9d0f1f78814b5b249ca2fe Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Thu, 23 Nov 2017 13:37:50 +0100 Subject: [PATCH] Reset bruteforce attempt table on successful login * only clear the entries that come from the same subnet, same action and same metadata Signed-off-by: Morris Jobke --- lib/base.php | 16 ++++++++--- lib/private/Security/Bruteforce/Throttler.php | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/base.php b/lib/base.php index dc09d0f533..6193b591ab 100644 --- a/lib/base.php +++ b/lib/base.php @@ -730,7 +730,7 @@ class OC { OC_User::setIncognitoMode(true); } - self::registerCacheHooks(); + self::registerCleanupHooks(); self::registerFilesystemHooks(); self::registerShareHooks(); self::registerEncryptionWrapper(); @@ -802,15 +802,23 @@ class OC { } /** - * register hooks for the cache + * register hooks for the cleanup of cache and bruteforce protection */ - public static function registerCacheHooks() { + public static function registerCleanupHooks() { //don't try to do this before we are properly setup if (\OC::$server->getSystemConfig()->getValue('installed', false) && !self::checkUpgrade(false)) { // NOTE: This will be replaced to use OCP $userSession = self::$server->getUserSession(); - $userSession->listen('\OC\User', 'postLogin', function () { + $userSession->listen('\OC\User', 'postLogin', function () use ($userSession) { + if (!defined('PHPUNIT_RUN')) { + // reset brute force delay for this IP address and username + $uid = \OC::$server->getUserSession()->getUser()->getUID(); + $request = \OC::$server->getRequest(); + $throttler = \OC::$server->getBruteForceThrottler(); + $throttler->resetDelay($request->getRemoteAddress(), 'login', ['user' => $uid]); + } + try { $cache = new \OC\Cache\File(); $cache->gc(); diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php index 1626cee8cb..f08b721d14 100644 --- a/lib/private/Security/Bruteforce/Throttler.php +++ b/lib/private/Security/Bruteforce/Throttler.php @@ -242,6 +242,33 @@ class Throttler { return (int) \ceil($firstDelay * 1000); } + /** + * Reset the throttling delay for an IP address, action and metadata + * + * @param string $ip + * @param string $action + * @param string $metadata + */ + public function resetDelay($ip, $action, $metadata) { + $ipAddress = new IpAddress($ip); + if ($this->isIPWhitelisted((string)$ipAddress)) { + return; + } + + $cutoffTime = (new \DateTime()) + ->sub($this->getCutoff(43200)) + ->getTimestamp(); + + $qb = $this->db->getQueryBuilder(); + $qb->delete('bruteforce_attempts') + ->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime))) + ->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet()))) + ->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action))) + ->andWhere($qb->expr()->eq('metadata', $qb->createNamedParameter(json_encode($metadata)))); + + $qb->execute(); + } + /** * Will sleep for the defined amount of time *