Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2022-07-01 12:18:27 +0300
committerJoas Schilling <coding@schilljs.com>2022-07-28 11:57:10 +0300
commitc0f47af2d04f4417d8f9792649266d5dd7a60a59 (patch)
tree6ccef5eeb05cdb33fd468b881e8277ff37875a95 /lib
parent472f4cad47f832ac0807ac3c4aa33d60a5bcbf31 (diff)
Add a public interface for the bruteforce throttler and register for injection
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Security/Bruteforce/Throttler.php8
-rw-r--r--lib/private/Server.php2
-rw-r--r--lib/public/Security/Bruteforce/IThrottler.php126
5 files changed, 133 insertions, 5 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 420bc89c735..8853c1f17f4 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -510,6 +510,7 @@ return array(
'OCP\\Search\\Result' => $baseDir . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => $baseDir . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => $baseDir . '/lib/public/Search/SearchResultEntry.php',
+ 'OCP\\Security\\Bruteforce\\IThrottler' => $baseDir . '/lib/public/Security/Bruteforce/IThrottler.php',
'OCP\\Security\\Bruteforce\\MaxDelayReached' => $baseDir . '/lib/public/Security/Bruteforce/MaxDelayReached.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => $baseDir . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => $baseDir . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 9a371b45743..5617430958d 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -543,6 +543,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Search\\Result' => __DIR__ . '/../../..' . '/lib/public/Search/Result.php',
'OCP\\Search\\SearchResult' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResult.php',
'OCP\\Search\\SearchResultEntry' => __DIR__ . '/../../..' . '/lib/public/Search/SearchResultEntry.php',
+ 'OCP\\Security\\Bruteforce\\IThrottler' => __DIR__ . '/../../..' . '/lib/public/Security/Bruteforce/IThrottler.php',
'OCP\\Security\\Bruteforce\\MaxDelayReached' => __DIR__ . '/../../..' . '/lib/public/Security/Bruteforce/MaxDelayReached.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => __DIR__ . '/../../..' . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index e37746eb6a2..299cab93eb3 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -36,6 +36,7 @@ use OC\Security\Normalizer\IpAddress;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IDBConnection;
+use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\Bruteforce\MaxDelayReached;
use Psr\Log\LoggerInterface;
@@ -52,11 +53,8 @@ use Psr\Log\LoggerInterface;
*
* @package OC\Security\Bruteforce
*/
-class Throttler {
+class Throttler implements IThrottler {
public const LOGIN_ACTION = 'login';
- public const MAX_DELAY = 25;
- public const MAX_DELAY_MS = 25000; // in milliseconds
- public const MAX_ATTEMPTS = 10;
/** @var IDBConnection */
private $db;
@@ -311,7 +309,7 @@ class Throttler {
*
* @param string $ip
*/
- public function resetDelayForIP($ip) {
+ public function resetDelayForIP(string $ip): void {
$cutoffTime = $this->getCutoffTimestamp();
$qb = $this->db->getQueryBuilder();
diff --git a/lib/private/Server.php b/lib/private/Server.php
index bcbb6ef6b00..842f72fa1d0 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -231,6 +231,7 @@ use OCP\Remote\Api\IApiFactory;
use OCP\Remote\IInstanceFactory;
use OCP\RichObjectStrings\IValidator;
use OCP\Route\IRouter;
+use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\IContentSecurityPolicyManager;
use OCP\Security\ICredentialsManager;
use OCP\Security\ICrypto;
@@ -1002,6 +1003,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(ITrustedDomainHelper::class, TrustedDomainHelper::class);
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Throttler', Throttler::class);
+ $this->registerAlias(IThrottler::class, Throttler::class);
$this->registerService('IntegrityCodeChecker', function (ContainerInterface $c) {
// IConfig and IAppManager requires a working database. This code
// might however be called when ownCloud is not yet setup.
diff --git a/lib/public/Security/Bruteforce/IThrottler.php b/lib/public/Security/Bruteforce/IThrottler.php
new file mode 100644
index 00000000000..6f492d6c59d
--- /dev/null
+++ b/lib/public/Security/Bruteforce/IThrottler.php
@@ -0,0 +1,126 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\Security\Bruteforce;
+
+/**
+ * Class Throttler implements the bruteforce protection for security actions in
+ * Nextcloud.
+ *
+ * It is working by logging invalid login attempts to the database and slowing
+ * down all login attempts from the same subnet. The max delay is 30 seconds and
+ * the starting delay are 200 milliseconds. (after the first failed login)
+ *
+ * This is based on Paragonie's AirBrake for Airship CMS. You can find the original
+ * code at https://github.com/paragonie/airship/blob/7e5bad7e3c0fbbf324c11f963fd1f80e59762606/src/Engine/Security/AirBrake.php
+ *
+ * @package OC\Security\Bruteforce
+ * @since 25.0.0
+ */
+interface IThrottler {
+ /**
+ * @since 25.0.0
+ */
+ public const MAX_DELAY = 25;
+
+ /**
+ * @since 25.0.0
+ */
+ public const MAX_DELAY_MS = 25000; // in milliseconds
+
+ /**
+ * @since 25.0.0
+ */
+ public const MAX_ATTEMPTS = 10;
+
+ /**
+ * Register a failed attempt to bruteforce a security control
+ *
+ * @param string $action
+ * @param string $ip
+ * @param array $metadata Optional metadata logged to the database
+ * @since 25.0.0
+ */
+ public function registerAttempt(string $action, string $ip, array $metadata = []): void;
+
+ /**
+ * Get the throttling delay (in milliseconds)
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @param float $maxAgeHours
+ * @return int
+ * @since 25.0.0
+ */
+ public function getAttempts(string $ip, string $action = '', float $maxAgeHours = 12): int;
+
+ /**
+ * Get the throttling delay (in milliseconds)
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return int
+ * @since 25.0.0
+ */
+ public function getDelay(string $ip, string $action = ''): int;
+
+ /**
+ * Reset the throttling delay for an IP address, action and metadata
+ *
+ * @param string $ip
+ * @param string $action
+ * @param array $metadata
+ * @since 25.0.0
+ */
+ public function resetDelay(string $ip, string $action, array $metadata): void;
+
+ /**
+ * Reset the throttling delay for an IP address
+ *
+ * @param string $ip
+ * @since 25.0.0
+ */
+ public function resetDelayForIP(string $ip): void;
+
+ /**
+ * Will sleep for the defined amount of time
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return int the time spent sleeping
+ * @since 25.0.0
+ */
+ public function sleepDelay(string $ip, string $action = ''): int;
+
+ /**
+ * Will sleep for the defined amount of time unless maximum was reached in the last 30 minutes
+ * In this case a "429 Too Many Request" exception is thrown
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return int the time spent sleeping
+ * @throws MaxDelayReached when reached the maximum
+ * @since 25.0.0
+ */
+ public function sleepDelayOrThrowOnMax(string $ip, string $action = ''): int;
+}