]> source.dussan.org Git - nextcloud-server.git/commitdiff
Throttle on public DAV endpoint
authorLukas Reschke <lukas@statuscode.ch>
Tue, 22 Jun 2021 17:54:13 +0000 (19:54 +0200)
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>
Wed, 23 Jun 2021 07:37:17 +0000 (07:37 +0000)
We should throttle whenever an invalid request is sent to the public WebDAV endpoint.

Signed-off-by: Lukas Reschke <lukas@statuscode.ch>
apps/dav/appinfo/v1/publicwebdav.php
apps/dav/lib/Connector/PublicAuth.php
apps/dav/tests/unit/Connector/PublicAuthTest.php

index a6ccad4752e114fd2d18a44ce93844cca91c2876..4fd394d2378e9c635a8a996ddc2782661434679d 100644 (file)
@@ -42,7 +42,8 @@ OC_Util::obEnd();
 $authBackend = new OCA\DAV\Connector\PublicAuth(
        \OC::$server->getRequest(),
        \OC::$server->getShareManager(),
-       \OC::$server->getSession()
+       \OC::$server->getSession(),
+       \OC::$server->getBruteForceThrottler()
 );
 $authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend);
 
index 0aab95b81580d47f00b13df091c63818473bd8a8..7d805b34d5c54af596fb0cddcf771000f8e29af2 100644 (file)
@@ -31,6 +31,7 @@
 
 namespace OCA\DAV\Connector;
 
+use OC\Security\Bruteforce\Throttler;
 use OCP\IRequest;
 use OCP\ISession;
 use OCP\Share\Exceptions\ShareNotFound;
@@ -44,6 +45,7 @@ use Sabre\DAV\Auth\Backend\AbstractBasic;
  * @package OCA\DAV\Connector
  */
 class PublicAuth extends AbstractBasic {
+       private const BRUTEFORCE_ACTION = 'public_webdav_auth';
 
        /** @var \OCP\Share\IShare */
        private $share;
@@ -57,17 +59,23 @@ class PublicAuth extends AbstractBasic {
        /** @var IRequest */
        private $request;
 
+       /** @var Throttler */
+       private $throttler;
+
        /**
         * @param IRequest $request
         * @param IManager $shareManager
         * @param ISession $session
+        * @param Throttler $throttler
         */
        public function __construct(IRequest $request,
                                                                IManager $shareManager,
-                                                               ISession $session) {
+                                                               ISession $session,
+                                                               Throttler $throttler) {
                $this->request = $request;
                $this->shareManager = $shareManager;
                $this->session = $session;
+               $this->throttler = $throttler;
 
                // setup realm
                $defaults = new \OCP\Defaults();
@@ -87,9 +95,12 @@ class PublicAuth extends AbstractBasic {
         * @throws \Sabre\DAV\Exception\NotAuthenticated
         */
        protected function validateUserPass($username, $password) {
+               $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), self::BRUTEFORCE_ACTION);
+
                try {
                        $share = $this->shareManager->getShareByToken($username);
                } catch (ShareNotFound $e) {
+                       $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress());
                        return false;
                }
 
@@ -114,11 +125,14 @@ class PublicAuth extends AbstractBasic {
                                                header('WWW-Authenticate: DummyBasic realm="' . $this->realm . '"');
                                                throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
                                        }
+
+                                       $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress());
                                        return false;
                                }
                        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
                                return true;
                        } else {
+                               $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress());
                                return false;
                        }
                } else {
index b8b59546eca9b882b66c9a3232e40c15b0da484b..d12ec4d373fb7a1279a570f8cd32e8bb46264e9d 100644 (file)
@@ -27,6 +27,7 @@
 
 namespace OCA\DAV\Tests\unit\Connector;
 
+use OC\Security\Bruteforce\Throttler;
 use OCP\IRequest;
 use OCP\ISession;
 use OCP\Share\Exceptions\ShareNotFound;
@@ -50,6 +51,8 @@ class PublicAuthTest extends \Test\TestCase {
        private $shareManager;
        /** @var \OCA\DAV\Connector\PublicAuth */
        private $auth;
+       /** @var Throttler|\PHPUnit\Framework\MockObject\MockObject */
+       private $throttler;
 
        /** @var string */
        private $oldUser;
@@ -66,11 +69,15 @@ class PublicAuthTest extends \Test\TestCase {
                $this->shareManager = $this->getMockBuilder(IManager::class)
                        ->disableOriginalConstructor()
                        ->getMock();
+               $this->shareManager = $this->getMockBuilder(Throttler::class)
+                       ->disableOriginalConstructor()
+                       ->getMock();
 
                $this->auth = new \OCA\DAV\Connector\PublicAuth(
                        $this->request,
                        $this->shareManager,
-                       $this->session
+                       $this->session,
+                       $this->throttler
                );
 
                // Store current user