From aabaee2359b25036f2a7fe35c4b57d861f0da3c8 Mon Sep 17 00:00:00 2001 From: Mathias Picker Date: Sat, 30 Dec 2023 01:32:51 +0100 Subject: [PATCH] write better tests and fix bugs --- packages/kit/src/runtime/server/page/csp.js | 18 +++-- .../kit/src/runtime/server/page/csp.spec.js | 76 +++++++++++++++++-- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/packages/kit/src/runtime/server/page/csp.js b/packages/kit/src/runtime/server/page/csp.js index 1a7aa2edae17..6bd55f9c0c38 100644 --- a/packages/kit/src/runtime/server/page/csp.js +++ b/packages/kit/src/runtime/server/page/csp.js @@ -128,19 +128,21 @@ class BaseProvider { /** @param {string} content */ add_script(content) { if (this.#script_needs_csp) { + const d = this.#directives; + if (this.#use_hashes) { - const hash = sha256(content) + const hash = sha256(content); this.#script_src.push(`sha256-${hash}`); - if (this.#script_src_elem.length === 0) { + if (d['script-src-elem']?.length) { this.#script_src_elem.push(`sha256-${hash}`); } } else { if (this.#script_src.length === 0) { this.#script_src.push(`nonce-${this.#nonce}`); } - if (this.#script_src_elem.length === 0) { + if (d['script-src-elem']?.length) { this.#script_src_elem.push(`nonce-${this.#nonce}`); } } @@ -150,25 +152,27 @@ class BaseProvider { /** @param {string} content */ add_style(content) { if (this.#style_needs_csp) { + const d = this.#directives; + if (this.#use_hashes) { const hash = sha256(content); this.#style_src.push(`sha256-${hash}`); - if (this.#style_src_attr.length === 0) { + if (d['style-src-attr']?.length) { this.#style_src_attr.push(`sha256-${hash}`); } - if (this.#style_src_elem.length === 0) { + if (d['style-src-elem']?.length) { this.#style_src_elem.push(`sha256-${hash}`); } } else { if (this.#style_src.length === 0) { this.#style_src.push(`nonce-${this.#nonce}`); } - if (this.#style_src_attr.length === 0) { + if (d['style-src-attr']?.length) { this.#style_src_attr.push(`nonce-${this.#nonce}`); } - if (this.#style_src_elem.length === 0) { + if (d['style-src-elem']?.length) { this.#style_src_elem.push(`nonce-${this.#nonce}`); } } diff --git a/packages/kit/src/runtime/server/page/csp.spec.js b/packages/kit/src/runtime/server/page/csp.spec.js index 21d4bc8ac80d..24a7afe74adb 100644 --- a/packages/kit/src/runtime/server/page/csp.spec.js +++ b/packages/kit/src/runtime/server/page/csp.spec.js @@ -153,6 +153,68 @@ test('skips frame-ancestors, report-uri, sandbox from meta tags', () => { ); }); +test('adds nonce to script-src-elem, style-src-attr and style-src-elem if necessary', () => { + const csp = new Csp( + { + mode: 'auto', + directives: { + 'script-src-elem': ['self'], + 'style-src-attr': ['self'], + 'style-src-elem': ['self'] + }, + reportOnly: {} + }, + { + prerender: false + } + ); + + csp.add_script(''); + csp.add_style(''); + + const csp_header = csp.csp_provider.get_header(); + assert.ok(csp_header.includes("script-src-elem 'self' 'nonce-")); + assert.ok(csp_header.includes("style-src-attr 'self' 'nonce-")); + assert.ok(csp_header.includes("style-src-elem 'self' 'nonce-")); +}); + +test('adds hash to script-src-elem, style-src-attr and style-src-elem if necessary during prerendering', () => { + const csp = new Csp( + { + mode: 'auto', + directives: { + 'script-src-elem': ['self'], + 'style-src-attr': ['self'], + 'style-src-elem': ['self'] + }, + reportOnly: {} + }, + { + prerender: true + } + ); + + csp.add_script(''); + csp.add_style(''); + + const csp_header = csp.csp_provider.get_header(); + assert.ok( + csp_header.includes( + "script-src-elem 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" + ) + ); + assert.ok( + csp_header.includes( + "style-src-attr 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" + ) + ); + assert.ok( + csp_header.includes( + "style-src-elem 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" + ) + ); +}); + test('adds unsafe-inline styles in dev', () => { // @ts-expect-error globalThis.__SVELTEKIT_DEV__ = true; @@ -161,10 +223,14 @@ test('adds unsafe-inline styles in dev', () => { { mode: 'hash', directives: { - 'default-src': ['self'] + 'default-src': ['self'], + 'style-src-attr': ['self'], + 'style-src-elem': ['self'] }, reportOnly: { 'default-src': ['self'], + 'style-src-attr': ['self'], + 'style-src-elem': ['self'], 'report-uri': ['/'] } }, @@ -177,12 +243,12 @@ test('adds unsafe-inline styles in dev', () => { assert.equal( csp.csp_provider.get_header(), - "default-src 'self'; style-src 'self' 'unsafe-inline'" + "default-src 'self'; style-src-attr 'self' 'unsafe-inline'; style-src-elem 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" ); assert.equal( csp.report_only_provider.get_header(), - "default-src 'self'; report-uri /; style-src 'self' 'unsafe-inline'" + "default-src 'self'; style-src-attr 'self' 'unsafe-inline'; style-src-elem 'self' 'unsafe-inline'; report-uri /; style-src 'self' 'unsafe-inline'" ); }); @@ -235,12 +301,12 @@ test('uses hashes when prerendering', () => { assert.equal( csp.csp_provider.get_header(), - "script-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='; script-src-elem 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" + "script-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" ); assert.equal( csp.report_only_provider.get_header(), - "script-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='; report-uri /; script-src-elem 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='" + "script-src 'self' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='; report-uri /" ); });