feat: add rate limiting for creating federated shares for non-trusted servers

Signed-off-by: Robin Appelman <robin@icewind.nl>
pull/62091/head
Robin Appelman 3 months ago
parent 3fe81069de
commit a97fe9d2ae
No known key found for this signature in database
GPG Key ID: 42B69D8A64526EFB
  1. 2
      apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
  2. 3
      apps/federatedfilesharing/lib/Controller/RequestHandlerController.php
  3. 1
      lib/composer/composer/autoload_classmap.php
  4. 1
      lib/composer/composer/autoload_static.php
  5. 55
      lib/private/AppFramework/Http/Attributes/FederationRateLimit.php

@ -7,6 +7,7 @@
namespace OCA\CloudFederationAPI\Controller;
use OC\AppFramework\Http\Attributes\FederationRateLimit;
use OC\Authentication\Token\PublicKeyTokenProvider;
use OC\OCM\OCMSignatoryManager;
use OCA\CloudFederationAPI\Config;
@ -107,6 +108,7 @@ class RequestHandlerController extends Controller {
#[PublicPage]
#[NoCSRFRequired]
#[BruteForceProtection(action: 'receiveFederatedShare')]
#[FederationRateLimit(limit: 5, period: 1200)]
public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) {
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
try {

@ -8,6 +8,7 @@
namespace OCA\FederatedFileSharing\Controller;
use OC\AppFramework\Http\Attributes\FederationRateLimit;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
@ -30,7 +31,6 @@ use OCP\IDBConnection;
use OCP\IRequest;
use OCP\Log\Audit\CriticalActionPerformedEvent;
use OCP\Server;
use OCP\Share;
use OCP\Share\Exceptions\ShareNotFound;
use Psr\Log\LoggerInterface;
@ -70,6 +70,7 @@ class RequestHandlerController extends OCSController {
*/
#[NoCSRFRequired]
#[PublicPage]
#[FederationRateLimit(limit: 5, period: 1200)]
public function createShare(
?string $remote = null,
?string $token = null,

@ -1127,6 +1127,7 @@ return array(
'OC\\AppFramework\\Bootstrap\\ServiceRegistration' => $baseDir . '/lib/private/AppFramework/Bootstrap/ServiceRegistration.php',
'OC\\AppFramework\\DependencyInjection\\DIContainer' => $baseDir . '/lib/private/AppFramework/DependencyInjection/DIContainer.php',
'OC\\AppFramework\\Http' => $baseDir . '/lib/private/AppFramework/Http.php',
'OC\\AppFramework\\Http\\Attributes\\FederationRateLimit' => $baseDir . '/lib/private/AppFramework/Http/Attributes/FederationRateLimit.php',
'OC\\AppFramework\\Http\\Attributes\\TwoFactorSetUpDoneRequired' => $baseDir . '/lib/private/AppFramework/Http/Attributes/TwoFactorSetUpDoneRequired.php',
'OC\\AppFramework\\Http\\Dispatcher' => $baseDir . '/lib/private/AppFramework/Http/Dispatcher.php',
'OC\\AppFramework\\Http\\Output' => $baseDir . '/lib/private/AppFramework/Http/Output.php',

@ -1168,6 +1168,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\AppFramework\\Bootstrap\\ServiceRegistration' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Bootstrap/ServiceRegistration.php',
'OC\\AppFramework\\DependencyInjection\\DIContainer' => __DIR__ . '/../../..' . '/lib/private/AppFramework/DependencyInjection/DIContainer.php',
'OC\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http.php',
'OC\\AppFramework\\Http\\Attributes\\FederationRateLimit' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Attributes/FederationRateLimit.php',
'OC\\AppFramework\\Http\\Attributes\\TwoFactorSetUpDoneRequired' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Attributes/TwoFactorSetUpDoneRequired.php',
'OC\\AppFramework\\Http\\Dispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Dispatcher.php',
'OC\\AppFramework\\Http\\Output' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Output.php',

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\AppFramework\Http\Attributes;
use Attribute;
use OC\OCM\OCMDiscoveryService;
use OCA\Federation\TrustedServers;
use OCP\AppFramework\Http\Attribute\AnonRateLimit;
use OCP\IRequest;
use OCP\Server;
/**
* Attribute for controller methods that want to limit the times a not logged-in
* guest can call the endpoint in a given time period.
*
* Unlike regular AnonRateLimit, signed requests from trusted servers are excluded from the rate limit.
*/
#[Attribute(Attribute::TARGET_METHOD)]
class FederationRateLimit extends AnonRateLimit {
private readonly OCMDiscoveryService $discoveryService;
private readonly ?TrustedServers $trustedServers;
public function __construct(int $limit, int $period) {
parent::__construct($limit, $period);
$this->discoveryService = Server::get(OCMDiscoveryService::class);
$this->trustedServers = Server::get(TrustedServers::class);
}
#[\Override]
public function shouldApply(IRequest $request): bool {
if ($this->trustedServers === null) {
return true;
}
try {
$signedRequest = $this->discoveryService->getIncomingSignedRequest();
if (!$signedRequest) {
return true;
}
$signedRequest->verify();
return !$this->trustedServers->isTrustedServer($signedRequest->getOrigin());
} catch (\Exception) {
// no or invalid signature
return true;
}
}
}
Loading…
Cancel
Save