Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat: Provide CSP nonce as <meta> element
This way we use the CSP nonce for dynamically loaded scripts.
Important to notice: The CSP nonce must NOT be injected in `content` as
this can lead to value exfiltration using e.g. side-channel attacts (CSS selectors).

Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Aug 13, 2024
commit 2916e5df7e08fc588e752beaf486d907112a34ee
1 change: 1 addition & 0 deletions core/templates/layout.base.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<meta name="theme-color" content="<?php p($theme->getColorPrimary()); ?>">
<meta name="csp-nonce" nonce="<?php p($_['cspNonce']); /* Do not pass into "content" to prevent exfiltration */ ?>">
<link rel="icon" href="<?php print_unescaped(image_path('core', 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon" href="<?php print_unescaped(image_path('core', 'favicon-touch.png')); ?>">
<link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path('core', 'favicon-mask.svg')); ?>" color="<?php p($theme->getColorPrimary()); ?>">
Expand Down
1 change: 1 addition & 0 deletions core/templates/layout.guest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
p($theme->getTitle());
?>
</title>
<meta name="csp-nonce" nonce="<?php p($_['cspNonce']); /* Do not pass into "content" to prevent exfiltration */ ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<?php if ($theme->getiTunesAppId() !== '') { ?>
<meta name="apple-itunes-app" content="app-id=<?php p($theme->getiTunesAppId()); ?>">
Expand Down
6 changes: 3 additions & 3 deletions core/templates/layout.initial-state.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
?>
<div id="initial-state-container" style="display: none;">
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
<?php }?>
<?php foreach ($_['initialStates'] as $app => $initialState) { ?>
<input type="hidden" id="initial-state-<?php p($app); ?>" value="<?php p(base64_encode($initialState)); ?>">
<?php }?>
</div>
1 change: 1 addition & 0 deletions core/templates/layout.public.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
p($theme->getTitle());
?>
</title>
<meta name="csp-nonce" nonce="<?php p($_['cspNonce']); /* Do not pass into "content" to prevent exfiltration */ ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<?php if ($theme->getiTunesAppId() !== '') { ?>
<meta name="apple-itunes-app" content="app-id=<?php p($theme->getiTunesAppId()); ?>">
Expand Down
1 change: 1 addition & 0 deletions core/templates/layout.user.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
p($theme->getTitle());
?>
</title>
<meta name="csp-nonce" nonce="<?php p($_['cspNonce']); /* Do not pass into "content" to prevent exfiltration */ ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<?php if ($theme->getiTunesAppId() !== '') { ?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public function getNonce(): string {
// Get the token from the CSRF token, we only use the "shared secret" part
// as the first part does not add any security / entropy to the token
// so it can be ignored to keep the nonce short while keeping the same randomness
$this->nonce = end(explode(':', ($this->csrfTokenManager->getToken()->getEncryptedValue())));
$csrfSecret = explode(':', ($this->csrfTokenManager->getToken()->getEncryptedValue()));
$this->nonce = end($csrfSecret);
} else {
$this->nonce = $this->request->server['CSP_NONCE'];
}
Expand Down
9 changes: 6 additions & 3 deletions lib/private/Template/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ class Base {
* @param string $template
* @param string $requestToken
* @param \OCP\IL10N $l10n
* @param string $cspNonce
* @param Defaults $theme
*/
public function __construct($template, $requestToken, $l10n, $theme) {
$this->vars = [];
$this->vars['requesttoken'] = $requestToken;
public function __construct($template, $requestToken, $l10n, $theme, $cspNonce) {
$this->vars = [
'cspNonce' => $cspNonce,
'requesttoken' => $requestToken,
];
$this->l10n = $l10n;
$this->template = $template;
$this->theme = $theme;
Expand Down
9 changes: 8 additions & 1 deletion lib/private/legacy/OC_Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public function __construct($app, $name, $renderAs = TemplateResponse::RENDER_AS
$theme = OC_Util::getTheme();

$requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
$cspNonce = \OCP\Server::get(\OC\Security\CSP\ContentSecurityPolicyNonceManager::class)->getNonce();

$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
$l10n = \OC::$server->getL10N($parts[0]);
Expand All @@ -56,7 +57,13 @@ public function __construct($app, $name, $renderAs = TemplateResponse::RENDER_AS
$this->path = $path;
$this->app = $app;

parent::__construct($template, $requestToken, $l10n, $themeDefaults);
parent::__construct(
$template,
$requestToken,
$l10n,
$themeDefaults,
$cspNonce,
);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use OC\Security\CSP\ContentSecurityPolicy;
use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
use OC\Security\CSRF\CsrfToken;
use OC\Security\CSRF\CsrfTokenManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
Expand Down