diff options
author | Daniel Kesselberg <mail@danielkesselberg.de> | 2023-08-15 18:58:52 +0200 |
---|---|---|
committer | Daniel Kesselberg <mail@danielkesselberg.de> | 2024-08-14 15:41:27 +0200 |
commit | 6e176840c882cfe11152de6350788d74374a54ae (patch) | |
tree | 36c324e1d646051ba36988094fdeb28371e39f1d /lib/private | |
parent | 0f10cabf2a7ff6652f7b29e81f3682fac941e647 (diff) | |
download | nextcloud-server-dept-remove-csrf-dependency-from-request.tar.gz nextcloud-server-dept-remove-csrf-dependency-from-request.zip |
feat: move csrf validation out of requestdept-remove-csrf-dependency-from-request
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
Diffstat (limited to 'lib/private')
-rw-r--r-- | lib/private/AppFramework/DependencyInjection/DIContainer.php | 5 | ||||
-rw-r--r-- | lib/private/AppFramework/Middleware/Security/CORSMiddleware.php | 4 | ||||
-rw-r--r-- | lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php | 4 | ||||
-rw-r--r-- | lib/private/EventSource.php | 4 | ||||
-rw-r--r-- | lib/private/EventSourceFactory.php | 7 | ||||
-rw-r--r-- | lib/private/Security/CSRF/CsrfValidator.php | 42 | ||||
-rw-r--r-- | lib/private/Server.php | 4 | ||||
-rw-r--r-- | lib/private/legacy/OC_JSON.php | 10 |
8 files changed, 73 insertions, 7 deletions
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index 208031b942f..2842a57d0e6 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -46,6 +46,7 @@ use OCP\ISession; use OCP\IURLGenerator; use OCP\IUserSession; use OCP\Security\Bruteforce\IThrottler; +use OCP\Security\CSRF\ICsrfValidator; use OCP\Security\Ip\IRemoteAddress; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -209,7 +210,8 @@ class DIContainer extends SimpleContainer implements IAppContainer { $c->get(IControllerMethodReflector::class), $c->get(IUserSession::class), $c->get(IThrottler::class), - $c->get(LoggerInterface::class) + $c->get(LoggerInterface::class), + $c->get(ICsrfValidator::class), ) ); $dispatcher->registerMiddleware( @@ -235,6 +237,7 @@ class DIContainer extends SimpleContainer implements IAppContainer { $c->get(AuthorizedGroupMapper::class), $server->get(IUserSession::class), $c->get(IRemoteAddress::class), + $c->get(ICsrfValidator::class), ); $dispatcher->registerMiddleware($securityMiddleware); $dispatcher->registerMiddleware( diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php index 3f0755b1b91..269c1e5c1dc 100644 --- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php @@ -21,6 +21,7 @@ use OCP\AppFramework\Middleware; use OCP\IRequest; use OCP\ISession; use OCP\Security\Bruteforce\IThrottler; +use OCP\Security\CSRF\ICsrfValidator; use Psr\Log\LoggerInterface; use ReflectionMethod; @@ -45,6 +46,7 @@ class CORSMiddleware extends Middleware { Session $session, IThrottler $throttler, private readonly LoggerInterface $logger, + private readonly ICsrfValidator $csrfValidator, ) { $this->request = $request; $this->reflector = $reflector; @@ -73,7 +75,7 @@ class CORSMiddleware extends Middleware { $pass = array_key_exists('PHP_AUTH_PW', $this->request->server) ? $this->request->server['PHP_AUTH_PW'] : null; // Allow to use the current session if a CSRF token is provided - if ($this->request->passesCSRFCheck()) { + if ($this->csrfValidator->validate($this->request)) { return; } // Skip CORS check for requests with AppAPI auth. diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php index b8de09072ce..6c03ecd96f5 100644 --- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php @@ -41,6 +41,7 @@ use OCP\INavigationManager; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; +use OCP\Security\CSRF\ICsrfValidator; use OCP\Security\Ip\IRemoteAddress; use OCP\Util; use Psr\Log\LoggerInterface; @@ -68,6 +69,7 @@ class SecurityMiddleware extends Middleware { private AuthorizedGroupMapper $groupAuthorizationMapper, private IUserSession $userSession, private IRemoteAddress $remoteAddress, + private readonly ICsrfValidator $csrfValidator, ) { } @@ -207,7 +209,7 @@ class SecurityMiddleware extends Middleware { return false; } - return !$this->request->passesCSRFCheck(); + return !$this->csrfValidator->validate($this->request); } private function isValidOCSRequest(): bool { diff --git a/lib/private/EventSource.php b/lib/private/EventSource.php index dbeda25049e..bf56003365c 100644 --- a/lib/private/EventSource.php +++ b/lib/private/EventSource.php @@ -10,6 +10,7 @@ namespace OC; use OCP\IEventSource; use OCP\IRequest; +use OCP\Security\CSRF\ICsrfValidator; class EventSource implements IEventSource { private bool $fallback = false; @@ -18,6 +19,7 @@ class EventSource implements IEventSource { public function __construct( private IRequest $request, + private ICsrfValidator $csrfValidator, ) { } @@ -54,7 +56,7 @@ class EventSource implements IEventSource { header('Location: '.\OC::$WEBROOT); exit(); } - if (!$this->request->passesCSRFCheck()) { + if (!$this->csrfValidator->validate($this->request)) { $this->send('error', 'Possible CSRF attack. Connection will be closed.'); $this->close(); exit(); diff --git a/lib/private/EventSourceFactory.php b/lib/private/EventSourceFactory.php index 57888b1be4c..ad6abee3cb8 100644 --- a/lib/private/EventSourceFactory.php +++ b/lib/private/EventSourceFactory.php @@ -12,14 +12,19 @@ namespace OC; use OCP\IEventSource; use OCP\IEventSourceFactory; use OCP\IRequest; +use OCP\Security\CSRF\ICsrfValidator; class EventSourceFactory implements IEventSourceFactory { public function __construct( private IRequest $request, + private ICsrfValidator $csrfValidator, ) { } public function create(): IEventSource { - return new EventSource($this->request); + return new EventSource( + $this->request, + $this->csrfValidator, + ); } } diff --git a/lib/private/Security/CSRF/CsrfValidator.php b/lib/private/Security/CSRF/CsrfValidator.php new file mode 100644 index 00000000000..b3f678f9518 --- /dev/null +++ b/lib/private/Security/CSRF/CsrfValidator.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\Security\CSRF; + +use OCP\IRequest; +use OCP\Security\CSRF\ICsrfValidator; + +class CsrfValidator implements ICsrfValidator { + public function __construct( + private CsrfTokenManager $csrfTokenManager + ) { + } + + public function validate(IRequest $request): bool { + if (!$request->passesStrictCookieCheck()) { + return false; + } + + if ($request->getHeader('OCS-APIRequest') !== '') { + return true; + } + + $token = $request->getParam('requesttoken', ''); + if ($token === '') { + $token = $request->getHeader('REQUESTTOKEN'); + } + if ($token === '') { + return false; + } + + $token = new CsrfToken($token); + + return $this->csrfTokenManager->isTokenValid($token); + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index a0072b43ee2..7cb40c032fc 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -98,6 +98,7 @@ use OC\Security\Crypto; use OC\Security\CSP\ContentSecurityPolicyManager; use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OC\Security\CSRF\CsrfTokenManager; +use OC\Security\CSRF\CsrfValidator; use OC\Security\CSRF\TokenStorage\SessionStorage; use OC\Security\Hasher; use OC\Security\Ip\RemoteAddress; @@ -209,6 +210,7 @@ use OCP\Remote\IInstanceFactory; use OCP\RichObjectStrings\IValidator; use OCP\Route\IRouter; use OCP\Security\Bruteforce\IThrottler; +use OCP\Security\CSRF\ICsrfValidator; use OCP\Security\IContentSecurityPolicyManager; use OCP\Security\ICredentialsManager; use OCP\Security\ICrypto; @@ -1408,6 +1410,8 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(\OCP\Security\Ip\IFactory::class, \OC\Security\Ip\Factory::class); + $this->registerAlias(ICsrfValidator::class, CsrfValidator::class); + $this->connectDispatcher(); } diff --git a/lib/private/legacy/OC_JSON.php b/lib/private/legacy/OC_JSON.php index a9682e2cce7..567a4b6b3d6 100644 --- a/lib/private/legacy/OC_JSON.php +++ b/lib/private/legacy/OC_JSON.php @@ -7,6 +7,8 @@ */ use OC\Authentication\TwoFactorAuth\Manager as TwoFactorAuthManager; +use OCP\IRequest; +use OCP\Security\CSRF\ICsrfValidator; class OC_JSON { /** @@ -45,12 +47,16 @@ class OC_JSON { * @suppress PhanDeprecatedFunction */ public static function callCheck() { - if (!\OC::$server->getRequest()->passesStrictCookieCheck()) { + $request = OC::$server->get(IRequest::class); + + if (!$request->passesStrictCookieCheck()) { header('Location: '.\OC::$WEBROOT); exit(); } - if (!\OC::$server->getRequest()->passesCSRFCheck()) { + $csrfValidator = OC::$server->get(ICsrfValidator::class); + + if (!$csrfValidator->validate($request)) { $l = \OC::$server->getL10N('lib'); self::error([ 'data' => [ 'message' => $l->t('Token expired. Please reload page.'), 'error' => 'token_expired' ]]); exit(); |