diff --git a/docs/content/1.documentation/1.getting-started/2.configuration.md b/docs/content/1.documentation/1.getting-started/2.configuration.md index 39de2016..c8f85131 100644 --- a/docs/content/1.documentation/1.getting-started/2.configuration.md +++ b/docs/content/1.documentation/1.getting-started/2.configuration.md @@ -45,15 +45,21 @@ security: { crossOriginEmbedderPolicy: 'require-corp', contentSecurityPolicy: { 'base-uri': ["'none'"], - 'default-src': ["'self'"], + 'default-src' : ["'none'"], 'connect-src': ["'self'", 'https:'], 'font-src': ["'self'", 'https:', 'data:'], + 'form-action': ["'self'"], + 'frame-ancestors': ["'self'"], + 'frame-src': ["'self'"], 'img-src': ["'self'", 'data:'], + 'manifest-src': ["'self'"], + 'media-src': ["'self'"], 'object-src': ["'none'"], 'script-src-attr': ["'none'"], 'style-src': ["'self'", 'https:', "'unsafe-inline'"], 'script-src': ["'self'", 'https:', "'unsafe-inline'", "'strict-dynamic'", "'nonce-{{nonce}}'"], - 'upgrade-insecure-requests': true + 'upgrade-insecure-requests': true, + 'worker-src': ["'self'"], }, originAgentCluster: '?1', referrerPolicy: 'no-referrer', diff --git a/docs/content/1.documentation/2.headers/1.csp.md b/docs/content/1.documentation/2.headers/1.csp.md index c2117055..8a5a90cb 100644 --- a/docs/content/1.documentation/2.headers/1.csp.md +++ b/docs/content/1.documentation/2.headers/1.csp.md @@ -45,7 +45,7 @@ You can also disable this header by `contentSecurityPolicy: false`. By default, Nuxt Security will set following value for this header: ```http -Content-Security-Policy: base-uri 'none'; default-src 'self'; connect-src 'self', https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic' 'nonce-{{nonce}}'; upgrade-insecure-requests; +Content-Security-Policy: base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic' 'nonce-{{nonce}}'; upgrade-insecure-requests; worker-src 'self'; ``` ## Available values diff --git a/docs/nuxt.config.ts b/docs/nuxt.config.ts index 1006a23e..fa1cb0fd 100755 --- a/docs/nuxt.config.ts +++ b/docs/nuxt.config.ts @@ -16,8 +16,12 @@ export default defineNuxtConfig({ headers: { contentSecurityPolicy: { 'img-src': ["'self'", "data:", 'https:'], // Allow https: external images - 'connect-src': process.env.NODE_ENV === 'development' ? ["'self'", 'https:', 'ws:'] : ["'self'", 'https:'], // Allow self and image api - 'frame-src': ['https://www.youtube-nocookie.com', 'https://stackblitz.com'], // Allow self and youtube and stackblitz iframes + 'connect-src': process.env.NODE_ENV === 'development' ? ["'self'", 'https:', 'ws:'] : ["'self'", 'https:'], // Allow websocket in dev mode + 'frame-src': ['https://www.youtube-nocookie.com', 'https://stackblitz.com'], // Allow youtube and stackblitz iframes + }, + permissionsPolicy: { + "picture-in-picture": ['self', '"https://www.youtube-nocookie.com"'], // Allow picture-in-picture for youtube + "fullscreen": ['self', '"https://www.youtube-nocookie.com"'], // Allow fullscreen for youtube }, crossOriginEmbedderPolicy: 'unsafe-none', // Allow youtube and stackblitz iframes } diff --git a/src/defaultConfig.ts b/src/defaultConfig.ts index b02f6cbf..7ea1a2e7 100644 --- a/src/defaultConfig.ts +++ b/src/defaultConfig.ts @@ -9,15 +9,21 @@ export const defaultSecurityConfig = (serverlUrl: string): ModuleOptions => ({ crossOriginEmbedderPolicy: 'require-corp', contentSecurityPolicy: { 'base-uri': ["'none'"], - 'default-src' : ["'self'"], + 'default-src' : ["'none'"], 'connect-src': ["'self'", 'https:'], 'font-src': ["'self'", 'https:', 'data:'], + 'form-action': ["'self'"], + 'frame-ancestors': ["'self'"], + 'frame-src': ["'self'"], 'img-src': ["'self'", 'data:'], + 'manifest-src': ["'self'"], + 'media-src': ["'self'"], 'object-src': ["'none'"], 'script-src-attr': ["'none'"], 'style-src': ["'self'", 'https:', "'unsafe-inline'"], 'script-src': ["'self'", 'https:', "'unsafe-inline'", "'strict-dynamic'", "'nonce-{{nonce}}'"], - 'upgrade-insecure-requests': true + 'upgrade-insecure-requests': true, + 'worker-src': ["'self'"], }, originAgentCluster: '?1', referrerPolicy: 'no-referrer', diff --git a/test/headers.test.ts b/test/headers.test.ts index a9f0cd4f..5c07280c 100644 --- a/test/headers.test.ts +++ b/test/headers.test.ts @@ -37,7 +37,7 @@ describe('[nuxt-security] Headers', async () => { expect(cspHeaderValue).toBeTruthy() expect(nonceValue).toBeDefined() expect(nonceValue).toHaveLength(24) - expect(cspHeaderValue).toBe(`base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic' 'nonce-${nonceValue}'; upgrade-insecure-requests;`) + expect(cspHeaderValue).toBe(`base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic' 'nonce-${nonceValue}'; upgrade-insecure-requests; worker-src 'self';`) }) it('has `cross-origin-embedder-policy` header set with correct default value', async () => { diff --git a/test/perRoute.test.ts b/test/perRoute.test.ts index ba27f028..d60442fb 100644 --- a/test/perRoute.test.ts +++ b/test/perRoute.test.ts @@ -29,7 +29,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -67,7 +67,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -105,7 +105,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -227,7 +227,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin-allow-popups') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -265,7 +265,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin-allow-popups') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -303,7 +303,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBeNull() expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBeNull() expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -341,7 +341,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBeNull() expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBeNull() expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -379,7 +379,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBeNull() expect(coop).toBe('same-origin') expect(coep).toBe('credentialless') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -417,7 +417,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-site') expect(coop).toBeNull() expect(coep).toBe('credentialless') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=31536000; includeSubDomains;') @@ -455,7 +455,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('cross-origin') expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https:; upgrade-insecure-requests; media-src 'none';") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'none'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https:; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=1; includeSubDomains; preload;') @@ -495,7 +495,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-site') expect(coop).toBeNull() expect(coep).toBe('credentialless') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=2;') @@ -535,7 +535,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-site') expect(coop).toBe('same-origin-allow-popups') expect(coep).toBe('credentialless') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer-when-downgrade') expect(sts).toBe('max-age=1; preload;') @@ -576,7 +576,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBeNull() expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src https:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self'; upgrade-insecure-requests;") + expect(csp).toBe("default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src https:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=10; preload;') @@ -614,7 +614,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { expect(corp).toBe('same-origin') expect(coop).toBe('same-origin') expect(coep).toBe('require-corp') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self'; upgrade-insecure-requests; manifest-src 'none';") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'none'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self'; upgrade-insecure-requests; worker-src 'self';") expect(oac).toBe('?1') expect(rp).toBe('no-referrer') expect(sts).toBe('max-age=10; includeSubDomains;') @@ -662,7 +662,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { const csp = headers.get('content-security-policy') const pp = headers.get('permissions-policy') - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src blob:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src blob:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") expect(pp).toBe('accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=self, document-domain=(), encrypted-media=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), layout-animations=(self), legacy-image-formats=(self), magnetometer=(), microphone=(), midi=(), oversized-images=(self), payment=(), picture-in-picture=(), publickey-credentials-get=(), speaker-selection=(), sync-xhr=(self), unoptimized-images=(self), unsized-media=(self), usb=(), screen-wake-lock=(), web-share=(), xr-spatial-tracking=()') }) @@ -958,7 +958,7 @@ describe('[nuxt-security] Per-route Configuration', async () => { const { headers } = res const csp = headers.get('content-security-policy') expect(csp).toBeDefined() - expect(csp).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests;") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") const rp = headers.get('referrer-policy') expect(rp).toBeDefined() expect(rp).toBe('no-referrer') diff --git a/test/runtimeHooks.test.ts b/test/runtimeHooks.test.ts index 8208ded2..29f03dd8 100644 --- a/test/runtimeHooks.test.ts +++ b/test/runtimeHooks.test.ts @@ -9,27 +9,27 @@ await setup({ describe('[nuxt-security] runtime hooks', () => { it('expect csp to be set to static values by the (deprecated) headers runtime hook', async () => { const res = await fetch('/headers-static') - expect(res.headers.get('Content-Security-Policy')).toMatchInlineSnapshot("\"base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' static-value.com; upgrade-insecure-requests; frame-ancestors * weird-value.com;\"") + expect(res.headers.get('Content-Security-Policy')).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors * weird-value.com; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' static-value.com; upgrade-insecure-requests; worker-src 'self';") expect(res.headers.get('X-Powered-By')).toBeNull() }) it('expect csp to be set to dynamically-fetched values by the (deprecated) headers runtime hook', async () => { const res = await fetch('/headers-dynamic') - expect(res.headers.get('Content-Security-Policy')).toMatchInlineSnapshot("\"base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' *.dynamic-value.com; upgrade-insecure-requests; frame-ancestors * weird-value.com;\"") + expect(res.headers.get('Content-Security-Policy')).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors * weird-value.com; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' *.dynamic-value.com; upgrade-insecure-requests; worker-src 'self';") expect(res.headers.get('X-Powered-By')).toBeNull() }) it('expect any security option to be modified by the new routeRules runtime hook', async () => { const res = await fetch('/rules-static') - expect(res.headers.get('Content-Security-Policy')).toMatchInlineSnapshot("\"base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' static-value.com; upgrade-insecure-requests; frame-ancestors * weird-value.com;\"") + expect(res.headers.get('Content-Security-Policy')).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors * weird-value.com; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' static-value.com; upgrade-insecure-requests; worker-src 'self';") expect(res.headers.get('X-Powered-By')).toEqual('Nuxt') }) it('expect any security option to be dynamically-fetched by the new routeRules runtime hook', async () => { const res = await fetch('/rules-dynamic') const csp = res.headers.get('Content-Security-Policy') - expect(csp).toMatchInlineSnapshot("\"base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' *.dynamic-value.com; upgrade-insecure-requests; frame-ancestors * weird-value.com;\"") + expect(csp).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors * weird-value.com; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' *.dynamic-value.com; upgrade-insecure-requests; worker-src 'self';") expect(res.headers.get('X-Powered-By')).toEqual('Nuxt') }) }) \ No newline at end of file diff --git a/test/ssrNonce.test.ts b/test/ssrNonce.test.ts index 6e8c9edd..796019c8 100644 --- a/test/ssrNonce.test.ts +++ b/test/ssrNonce.test.ts @@ -63,7 +63,7 @@ describe('[nuxt-security] Nonce', async () => { const noncesInCsp = cspHeaderValue?.match(/'nonce-(.*?)'/)?.length ?? 0 expect(noncesInCsp).toBe(0) - expect(cspHeaderValue).toBe("base-uri 'none'; default-src 'self'; connect-src 'self' https:; font-src 'self' https: data:; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self'; script-src 'self' 'strict-dynamic'; upgrade-insecure-requests;") + expect(cspHeaderValue).toBe("base-uri 'none'; default-src 'none'; connect-src 'self' https:; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data:; manifest-src 'self'; media-src 'self'; object-src 'none'; script-src-attr 'none'; style-src 'self'; script-src 'self' 'strict-dynamic'; upgrade-insecure-requests; worker-src 'self';") }) it('injects `nonce` attribute in style tags', async () => {