mirror of
https://github.com/nextcloud/server.git
synced 2026-06-06 15:23:17 -04:00
Merge pull request #33081 from nextcloud/techdebt/noid/ocp-security-bruteforce-ithrottler
Add a public interface for the bruteforce throttler and register for …
This commit is contained in:
commit
7566692e3b
5 changed files with 133 additions and 5 deletions
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
126
lib/public/Security/Bruteforce/IThrottler.php
Normal file
126
lib/public/Security/Bruteforce/IThrottler.php
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue