aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorDaniel Kesselberg <mail@danielkesselberg.de>2023-08-15 18:58:52 +0200
committerDaniel Kesselberg <mail@danielkesselberg.de>2024-08-14 15:41:27 +0200
commit6e176840c882cfe11152de6350788d74374a54ae (patch)
tree36c324e1d646051ba36988094fdeb28371e39f1d /lib/private
parent0f10cabf2a7ff6652f7b29e81f3682fac941e647 (diff)
downloadnextcloud-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.php5
-rw-r--r--lib/private/AppFramework/Middleware/Security/CORSMiddleware.php4
-rw-r--r--lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php4
-rw-r--r--lib/private/EventSource.php4
-rw-r--r--lib/private/EventSourceFactory.php7
-rw-r--r--lib/private/Security/CSRF/CsrfValidator.php42
-rw-r--r--lib/private/Server.php4
-rw-r--r--lib/private/legacy/OC_JSON.php10
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();