From 7d80e200d9c9085760a9ccd3212eb847cfd8714b Mon Sep 17 00:00:00 2001 From: Mathias Picker Date: Sat, 30 Dec 2023 00:12:38 +0100 Subject: [PATCH 01/20] add nonce to script-src-elem csp directive if defined --- packages/kit/src/runtime/server/page/csp.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/runtime/server/page/csp.js b/packages/kit/src/runtime/server/page/csp.js index a1a530d9d62e..4384506823ca 100644 --- a/packages/kit/src/runtime/server/page/csp.js +++ b/packages/kit/src/runtime/server/page/csp.js @@ -40,6 +40,9 @@ class BaseProvider { /** @type {import('types').Csp.Source[]} */ #script_src; + /** @type {import('types').Csp.Source[]} */ + #script_src_elem; + /** @type {import('types').Csp.Source[]} */ #style_src; @@ -79,6 +82,7 @@ class BaseProvider { } this.#script_src = []; + this.#script_src_elem = []; this.#style_src = []; const effective_script_src = d['script-src'] || d['default-src']; @@ -103,8 +107,13 @@ class BaseProvider { if (this.#script_needs_csp) { if (this.#use_hashes) { this.#script_src.push(`sha256-${sha256(content)}`); - } else if (this.#script_src.length === 0) { - this.#script_src.push(`nonce-${this.#nonce}`); + } else { + if (this.#script_src.length === 0) { + this.#script_src.push(`nonce-${this.#nonce}`); + } + if (this.#script_src_elem.length === 0) { + this.#script_src_elem.push(`nonce-${this.#nonce}`); + } } } } @@ -146,6 +155,13 @@ class BaseProvider { ]; } + if (this.#script_src_elem.length > 0) { + directives['script-src-elem'] = [ + ...(directives['script-src-elem'] || []), + ...this.#script_src_elem + ]; + } + for (const key in directives) { if (is_meta && (key === 'frame-ancestors' || key === 'report-uri' || key === 'sandbox')) { // these values cannot be used with a tag From c4cf0efb681e471dd5e688552ae5f1558520cd3e Mon Sep 17 00:00:00 2001 From: Mathias Picker Date: Sat, 30 Dec 2023 00:19:44 +0100 Subject: [PATCH 02/20] added changeset --- .changeset/giant-years-drum.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/giant-years-drum.md diff --git a/.changeset/giant-years-drum.md b/.changeset/giant-years-drum.md new file mode 100644 index 000000000000..b1f0b9fbed56 --- /dev/null +++ b/.changeset/giant-years-drum.md @@ -0,0 +1,5 @@ +--- +"@sveltejs/kit": patch +--- + +nonce is automatically added if script-src-elem is defined in csp directives config From b168c24d59489332e34ab6bfe00bfe7cf765acb9 Mon Sep 17 00:00:00 2001 From: Mathias Picker Date: Sat, 30 Dec 2023 00:40:52 +0100 Subject: [PATCH 03/20] also handle hashes and style-src-attr and style-src-elem --- packages/kit/src/runtime/server/page/csp.js | 92 +++++++++++++++++---- 1 file changed, 76 insertions(+), 16 deletions(-) diff --git a/packages/kit/src/runtime/server/page/csp.js b/packages/kit/src/runtime/server/page/csp.js index 4384506823ca..50ef96bcf517 100644 --- a/packages/kit/src/runtime/server/page/csp.js +++ b/packages/kit/src/runtime/server/page/csp.js @@ -46,6 +46,12 @@ class BaseProvider { /** @type {import('types').Csp.Source[]} */ #style_src; + /** @type {import('types').Csp.Source[]} */ + #style_src_attr; + + /** @type {import('types').Csp.Source[]} */ + #style_src_elem; + /** @type {string} */ #nonce; @@ -60,6 +66,18 @@ class BaseProvider { const d = this.#directives; + this.#script_src = []; + this.#script_src_elem = []; + this.#style_src = []; + this.#style_src_attr = []; + this.#style_src_elem = []; + + const effective_script_src = d['script-src'] || d['default-src']; + const script_src_elem = d['script-src-elem']; + const effective_style_src = d['style-src'] || d['default-src']; + const style_src_elem = d['style-src-elem']; + const style_src_attr = d['style-src-attr']; + if (__SVELTEKIT_DEV__) { // remove strict-dynamic in dev... // TODO reinstate this if we can figure out how to make strict-dynamic work @@ -73,29 +91,34 @@ class BaseProvider { // if (d['script-src'].length === 0) delete d['script-src']; // } - const effective_style_src = d['style-src'] || d['default-src']; - // ...and add unsafe-inline so we can inject