diff --git a/apps/theming/appinfo/app.php b/apps/theming/appinfo/app.php index 03fdbc9d00..152504c417 100644 --- a/apps/theming/appinfo/app.php +++ b/apps/theming/appinfo/app.php @@ -47,7 +47,7 @@ $linkToJs = \OC::$server->getURLGenerator()->linkToRoute( 'script', [ 'src' => $linkToJs, - 'nonce' => base64_encode(\OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue()) + 'nonce' => \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() ], '' ); diff --git a/core/templates/layout.base.php b/core/templates/layout.base.php index d6fda96dd6..3f13523afc 100644 --- a/core/templates/layout.base.php +++ b/core/templates/layout.base.php @@ -19,7 +19,7 @@ - + diff --git a/core/templates/layout.guest.php b/core/templates/layout.guest.php index a93224af5c..6d46ac6cf2 100644 --- a/core/templates/layout.guest.php +++ b/core/templates/layout.guest.php @@ -20,7 +20,7 @@ - + diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index d3dcd979d3..d258e3582d 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -27,7 +27,7 @@ - + diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c10f1ca7e5..879630890d 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -674,6 +674,7 @@ return array( 'OC\\Security\\Bruteforce\\Throttler' => $baseDir . '/lib/private/Security/Bruteforce/Throttler.php', 'OC\\Security\\CSP\\ContentSecurityPolicy' => $baseDir . '/lib/private/Security/CSP/ContentSecurityPolicy.php', 'OC\\Security\\CSP\\ContentSecurityPolicyManager' => $baseDir . '/lib/private/Security/CSP/ContentSecurityPolicyManager.php', + 'OC\\Security\\CSP\\ContentSecurityPolicyNounceManager' => $baseDir . '/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php', 'OC\\Security\\CSRF\\CsrfToken' => $baseDir . '/lib/private/Security/CSRF/CsrfToken.php', 'OC\\Security\\CSRF\\CsrfTokenGenerator' => $baseDir . '/lib/private/Security/CSRF/CsrfTokenGenerator.php', 'OC\\Security\\CSRF\\CsrfTokenManager' => $baseDir . '/lib/private/Security/CSRF/CsrfTokenManager.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 4b7020b59b..281f3d46f0 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -704,6 +704,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Security\\Bruteforce\\Throttler' => __DIR__ . '/../../..' . '/lib/private/Security/Bruteforce/Throttler.php', 'OC\\Security\\CSP\\ContentSecurityPolicy' => __DIR__ . '/../../..' . '/lib/private/Security/CSP/ContentSecurityPolicy.php', 'OC\\Security\\CSP\\ContentSecurityPolicyManager' => __DIR__ . '/../../..' . '/lib/private/Security/CSP/ContentSecurityPolicyManager.php', + 'OC\\Security\\CSP\\ContentSecurityPolicyNounceManager' => __DIR__ . '/../../..' . '/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php', 'OC\\Security\\CSRF\\CsrfToken' => __DIR__ . '/../../..' . '/lib/private/Security/CSRF/CsrfToken.php', 'OC\\Security\\CSRF\\CsrfTokenGenerator' => __DIR__ . '/../../..' . '/lib/private/Security/CSRF/CsrfTokenGenerator.php', 'OC\\Security\\CSRF\\CsrfTokenManager' => __DIR__ . '/../../..' . '/lib/private/Security/CSRF/CsrfTokenManager.php', diff --git a/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php new file mode 100644 index 0000000000..0482ea49e5 --- /dev/null +++ b/lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php @@ -0,0 +1,54 @@ + + * + * @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 . + * + */ + +namespace OC\Security\CSP; + +use OC\Security\CSRF\CsrfTokenManager; + +/** + * @package OC\Security\CSP + */ +class ContentSecurityPolicyNonceManager { + /** @var CsrfTokenManager */ + private $csrfTokenManager; + /** @var string */ + private $nonce = ''; + + /** + * @param CsrfTokenManager $csrfTokenManager + */ + public function __construct(CsrfTokenManager $csrfTokenManager) { + $this->csrfTokenManager = $csrfTokenManager; + } + + /** + * Returns the current CSP nounce + * + * @return string + */ + public function getNonce() { + if($this->nonce === '') { + $this->nonce = base64_encode($this->csrfTokenManager->getToken()->getEncryptedValue()); + } + + return $this->nonce; + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index 11558118d5..1ccc27802d 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -73,6 +73,7 @@ use OC\Security\Bruteforce\Throttler; use OC\Security\CertificateManager; use OC\Security\CSP\ContentSecurityPolicyManager; use OC\Security\Crypto; +use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OC\Security\CSRF\CsrfTokenGenerator; use OC\Security\CSRF\CsrfTokenManager; use OC\Security\CSRF\TokenStorage\SessionStorage; @@ -708,6 +709,11 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('ContentSecurityPolicyManager', function (Server $c) { return new ContentSecurityPolicyManager(); }); + $this->registerService('ContentSecurityPolicyNonceManager', function(Server $c) { + return new ContentSecurityPolicyNonceManager( + $c->getCsrfTokenManager() + ); + }); $this->registerService('ShareManager', function(Server $c) { $config = $c->getConfig(); $factoryClass = $config->getSystemValue('sharing.managerFactory', '\OC\Share20\ProviderFactory'); @@ -1405,6 +1411,13 @@ class Server extends ServerContainer implements IServerContainer { return $this->query('ContentSecurityPolicyManager'); } + /** + * @return ContentSecurityPolicyNonceManager + */ + public function getContentSecurityPolicyNonceManager() { + return $this->query('ContentSecurityPolicyNonceManager'); + } + /** * Not a public API as of 8.2, wait for 9.0 * diff --git a/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php new file mode 100644 index 0000000000..39d24807d5 --- /dev/null +++ b/tests/lib/Security/CSP/ContentSecurityPolicyNonceManagerTest.php @@ -0,0 +1,57 @@ + + * + * @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 . + * + */ + +namespace Test\Security\CSP; + +use OC\Security\CSP\ContentSecurityPolicyNonceManager; +use OC\Security\CSRF\CsrfToken; +use OC\Security\CSRF\CsrfTokenManager; +use Test\TestCase; + +class ContentSecurityPolicyNonceManagerTest extends TestCase { + /** @var CsrfTokenManager */ + private $csrfTokenManager; + /** @var ContentSecurityPolicyNonceManager */ + private $nonceManager; + + public function setUp() { + $this->csrfTokenManager = $this->createMock(CsrfTokenManager::class); + $this->nonceManager = new ContentSecurityPolicyNonceManager( + $this->csrfTokenManager + ); + } + + public function testGetNonce() { + $token = $this->createMock(CsrfToken::class); + $token + ->expects($this->once()) + ->method('getEncryptedValue') + ->willReturn('MyToken'); + + $this->csrfTokenManager + ->expects($this->once()) + ->method('getToken') + ->willReturn($token); + + $this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce()); + $this->assertSame('TXlUb2tlbg==', $this->nonceManager->getNonce()); + } +}