mirror of
https://github.com/nextcloud/server.git
synced 2026-04-22 23:03:00 -04:00
Allow to set a strict-dynamic CSP through the API
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
parent
0825c3ea34
commit
bd03dd37be
5 changed files with 43 additions and 0 deletions
|
|
@ -244,4 +244,11 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy
|
|||
public function setReportTo(array $reportTo) {
|
||||
$this->reportTo = $reportTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $strictDynamicAllowed
|
||||
*/
|
||||
public function setStrictDynamicAllowed(bool $strictDynamicAllowed) {
|
||||
$this->strictDynamicAllowed = $strictDynamicAllowed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
|
|||
protected $inlineScriptAllowed = false;
|
||||
/** @var bool Whether eval in JS scripts is allowed */
|
||||
protected $evalScriptAllowed = false;
|
||||
/** @var bool Whether strict-dynamic should be set */
|
||||
protected $strictDynamicAllowed = null;
|
||||
/** @var array Domains from which scripts can get loaded */
|
||||
protected $allowedScriptDomains = [
|
||||
'\'self\'',
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ class EmptyContentSecurityPolicy {
|
|||
protected $inlineScriptAllowed = null;
|
||||
/** @var string Whether JS nonces should be used */
|
||||
protected $useJsNonce = null;
|
||||
/** @var bool Whether strict-dynamic should be used */
|
||||
protected $strictDynamicAllowed = null;
|
||||
/**
|
||||
* @var bool Whether eval in JS scripts is allowed
|
||||
* TODO: Disallow per default
|
||||
|
|
@ -93,6 +95,16 @@ class EmptyContentSecurityPolicy {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $state
|
||||
* @return EmptyContentSecurityPolicy
|
||||
* @since 24.0.0
|
||||
*/
|
||||
public function useStrictDynamic(bool $state = false): self {
|
||||
$this->strictDynamicAllowed = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the according JS nonce
|
||||
* This method is only for CSPMiddleware, custom values are ignored in mergePolicies of ContentSecurityPolicyManager
|
||||
|
|
@ -438,6 +450,9 @@ class EmptyContentSecurityPolicy {
|
|||
if (!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) {
|
||||
$policy .= 'script-src ';
|
||||
if (is_string($this->useJsNonce)) {
|
||||
if ($this->strictDynamicAllowed) {
|
||||
$policy .= '\'strict-dynamic\' ';
|
||||
}
|
||||
$policy .= '\'nonce-'.base64_encode($this->useJsNonce).'\'';
|
||||
$allowedScriptDomains = array_flip($this->allowedScriptDomains);
|
||||
unset($allowedScriptDomains['\'self\'']);
|
||||
|
|
|
|||
|
|
@ -472,4 +472,21 @@ class ContentSecurityPolicyTest extends \Test\TestCase {
|
|||
$this->contentSecurityPolicy->allowEvalScript(true);
|
||||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
|
||||
}
|
||||
|
||||
public function testGetPolicyNonce() {
|
||||
$nonce = 'my-nonce';
|
||||
$expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-".base64_encode($nonce) . "';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'";
|
||||
|
||||
$this->contentSecurityPolicy->useJsNonce($nonce);
|
||||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
|
||||
}
|
||||
|
||||
public function testGetPolicyNonceStrictDynamic() {
|
||||
$nonce = 'my-nonce';
|
||||
$expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-".base64_encode($nonce) . "';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'";
|
||||
|
||||
$this->contentSecurityPolicy->useJsNonce($nonce);
|
||||
$this->contentSecurityPolicy->useStrictDynamic(true);
|
||||
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ class ContentSecurityPolicyManagerTest extends TestCase {
|
|||
$policy = new \OCP\AppFramework\Http\ContentSecurityPolicy();
|
||||
$policy->addAllowedFontDomain('mydomain.com');
|
||||
$policy->addAllowedImageDomain('anotherdomain.de');
|
||||
$policy->useStrictDynamic(true);
|
||||
|
||||
$e->addPolicy($policy);
|
||||
});
|
||||
|
|
@ -117,6 +118,7 @@ class ContentSecurityPolicyManagerTest extends TestCase {
|
|||
$expected->addAllowedImageDomain('example.org');
|
||||
$expected->addAllowedChildSrcDomain('childdomain');
|
||||
$expected->addAllowedFormActionDomain('thirdDomain');
|
||||
$expected->useStrictDynamic(true);
|
||||
$expectedStringPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: anotherdomain.de example.org;font-src 'self' data: mydomain.com example.com anotherFontDomain;connect-src 'self';media-src 'self';child-src childdomain;frame-ancestors 'self';form-action 'self' thirdDomain";
|
||||
|
||||
$this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy());
|
||||
|
|
|
|||
Loading…
Reference in a new issue