Skip to content

Commit f1b3c8f

Browse files
committed
Allow "wasm-unsafe-eval" in CSP
If a page has a Content Security Policy header and the `script-src` (or `default-src`) directive does not contain neither `wasm-unsafe-eval` nor `unsafe-eval` loading and executing WebAssembly is blocked in the page (although it is still possible to load and execute WebAssembly in a worker thread). Although the Nextcloud classes to manage the CSP already supported allowing `unsafe-eval` this affects not only WebAssembly, but also the `eval` operation in JavaScript. To make possible to allow WebAssembly execution without allowing JavaScript `eval` this commit adds support for allowing `wasm-unsafe-eval`. Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
1 parent 527de8a commit f1b3c8f

File tree

6 files changed

+49
-1
lines changed

6 files changed

+49
-1
lines changed

lib/private/Security/CSP/ContentSecurityPolicy.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ public function setEvalScriptAllowed(bool $evalScriptAllowed) {
6464
$this->evalScriptAllowed = $evalScriptAllowed;
6565
}
6666

67+
/**
68+
* @return boolean
69+
*/
70+
public function isEvalWasmAllowed(): ?bool {
71+
return $this->evalWasmAllowed;
72+
}
73+
74+
/**
75+
* @param boolean $evalWasmAllowed
76+
*/
77+
public function setEvalWasmAllowed(bool $evalWasmAllowed): void {
78+
$this->evalWasmAllowed = $evalWasmAllowed;
79+
}
80+
6781
/**
6882
* @return array
6983
*/

lib/public/AppFramework/Http/ContentSecurityPolicy.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
4444
protected $inlineScriptAllowed = false;
4545
/** @var bool Whether eval in JS scripts is allowed */
4646
protected $evalScriptAllowed = false;
47+
/** @var bool Whether WebAssembly compilation is allowed */
48+
protected ?bool $evalWasmAllowed = false;
4749
/** @var bool Whether strict-dynamic should be set */
4850
protected $strictDynamicAllowed = false;
4951
/** @var array Domains from which scripts can get loaded */

lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class EmptyContentSecurityPolicy {
4949
* @link https://github.com/owncloud/core/issues/11925
5050
*/
5151
protected $evalScriptAllowed = null;
52+
/** @var bool Whether WebAssembly compilation is allowed */
53+
protected ?bool $evalWasmAllowed = null;
5254
/** @var array Domains from which scripts can get loaded */
5355
protected $allowedScriptDomains = null;
5456
/**
@@ -130,6 +132,17 @@ public function allowEvalScript($state = true) {
130132
return $this;
131133
}
132134

135+
/**
136+
* Whether WebAssembly compilation is allowed or forbidden
137+
* @param bool $state
138+
* @return $this
139+
* @since 27.0.0
140+
*/
141+
public function allowEvalWasm(bool $state = true) {
142+
$this->evalWasmAllowed = $state;
143+
return $this;
144+
}
145+
133146
/**
134147
* Allows to execute JavaScript files from a specific domain. Use * to
135148
* allow JavaScript from all domains.
@@ -447,7 +460,7 @@ public function buildPolicy() {
447460
$policy .= "base-uri 'none';";
448461
$policy .= "manifest-src 'self';";
449462

450-
if (!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) {
463+
if (!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed || $this->evalWasmAllowed) {
451464
$policy .= 'script-src ';
452465
if (is_string($this->useJsNonce)) {
453466
if ($this->strictDynamicAllowed) {
@@ -470,6 +483,9 @@ public function buildPolicy() {
470483
if ($this->evalScriptAllowed) {
471484
$policy .= ' \'unsafe-eval\'';
472485
}
486+
if ($this->evalWasmAllowed) {
487+
$policy .= ' \'wasm-unsafe-eval\'';
488+
}
473489
$policy .= ';';
474490
}
475491

lib/public/AppFramework/Http/StrictContentSecurityPolicy.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class StrictContentSecurityPolicy extends EmptyContentSecurityPolicy {
4646
protected $inlineScriptAllowed = false;
4747
/** @var bool Whether eval in JS scripts is allowed */
4848
protected $evalScriptAllowed = false;
49+
/** @var bool Whether WebAssembly compilation is allowed */
50+
protected ?bool $evalWasmAllowed = false;
4951
/** @var array Domains from which scripts can get loaded */
5052
protected $allowedScriptDomains = [
5153
'\'self\'',

tests/lib/AppFramework/Http/ContentSecurityPolicyTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,13 @@ public function testGetPolicyUnsafeEval() {
472472
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
473473
}
474474

475+
public function testGetPolicyUnsafeWasmEval() {
476+
$expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'wasm-unsafe-eval';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'";
477+
478+
$this->contentSecurityPolicy->allowEvalWasm(true);
479+
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
480+
}
481+
475482
public function testGetPolicyNonce() {
476483
$nonce = 'my-nonce';
477484
$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'";

tests/lib/AppFramework/Http/EmptyContentSecurityPolicyTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ public function testGetPolicyScriptAllowInlineAndEval() {
9191
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
9292
}
9393

94+
public function testGetPolicyScriptAllowWasmEval() {
95+
$expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'wasm-unsafe-eval';frame-ancestors 'none'";
96+
97+
$this->contentSecurityPolicy->allowEvalWasm(true);
98+
$this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy());
99+
}
100+
94101
public function testGetPolicyStyleDomainValid() {
95102
$expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.owncloud.com;frame-ancestors 'none'";
96103

0 commit comments

Comments
 (0)