+
+
+
\ No newline at end of file
diff --git a/test/fixtures/ssrNonce/pages/server-component.vue b/test/fixtures/ssrNonce/pages/server-component.vue
new file mode 100644
index 00000000..ef3098ad
--- /dev/null
+++ b/test/fixtures/ssrNonce/pages/server-component.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/test/ssrNonce.test.ts b/test/ssrNonce.test.ts
index a9d99412..1c8d8cd3 100644
--- a/test/ssrNonce.test.ts
+++ b/test/ssrNonce.test.ts
@@ -97,4 +97,18 @@ describe('[nuxt-security] Nonce', async () => {
expect(injectedNonces).toBe(null)
expect(cspNonces).toBe(null)
})
+
+ it('works with server-only components', async () => {
+ const res = await fetch('/server-component')
+
+ const cspHeaderValue = res.headers.get('content-security-policy')
+ const nonce = cspHeaderValue?.match(/'nonce-(.*?)'/)?.[1]
+
+ const text = await res.text()
+
+ expect(res).toBeDefined()
+ expect(res).toBeTruthy()
+ expect(nonce).toBeDefined()
+ expect(text).toMatch(`${nonce}`)
+ })
})
From c38a710fbdf6a091e8eec2eb6c5be89208f7adae Mon Sep 17 00:00:00 2001
From: Pascal Sthamer <10992664+P4sca1@users.noreply.github.com>
Date: Wed, 31 Jul 2024 13:16:31 +0200
Subject: [PATCH 3/8] fix: log warning when removing static nonce from CSP
header
---
src/runtime/nitro/plugins/50-updateCsp.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/runtime/nitro/plugins/50-updateCsp.ts b/src/runtime/nitro/plugins/50-updateCsp.ts
index 17cc7aa1..c16f793c 100644
--- a/src/runtime/nitro/plugins/50-updateCsp.ts
+++ b/src/runtime/nitro/plugins/50-updateCsp.ts
@@ -1,6 +1,7 @@
import { defineNitroPlugin } from '#imports'
import { resolveSecurityRules } from '../context'
import type { ContentSecurityPolicyValue } from '../../../types/headers'
+import { useLogger } from '@nuxt/kit'
/**
* This plugin updates the CSP directives with the nonce and hashes generated by the server.
@@ -23,6 +24,8 @@ export default defineNitroPlugin((nitroApp) => {
})
function updateCspVariables(csp: ContentSecurityPolicyValue, nonce?: string, scriptHashes?: Set, styleHashes?: Set) {
+ const logger = useLogger('nuxt-security')
+
const generatedCsp = Object.fromEntries(Object.entries(csp).map(([directive, value]) => {
// Return boolean values unchanged
if (typeof value === 'boolean') {
@@ -31,7 +34,13 @@ function updateCspVariables(csp: ContentSecurityPolicyValue, nonce?: string, scr
// Make sure nonce placeholders are eliminated
const sources = (typeof value === 'string') ? value.split(' ').map(token => token.trim()).filter(token => token) : value
const modifiedSources = sources
- .filter(source => !source.startsWith("'nonce-") || source === "'nonce-{{nonce}}'")
+ .filter(source => {
+ if (source.startsWith("'nonce-") && source !== "'nonce-{{nonce}}'") {
+ logger.warn('Removing static nonce from CSP header.')
+ return false
+ }
+ return true
+ })
.map(source => {
if (source === "'nonce-{{nonce}}'") {
return nonce ? `'nonce-${nonce}'` : ''
From 2b0cf0f84ea74b5496dc10b9d8f710d4e1d1408e Mon Sep 17 00:00:00 2001
From: Pascal Sthamer <10992664+P4sca1@users.noreply.github.com>
Date: Wed, 31 Jul 2024 13:31:21 +0200
Subject: [PATCH 4/8] fix: skip nonce generation and csp header update for
NuxtIsland requests
---
src/runtime/nitro/plugins/40-cspSsrNonce.ts | 29 ++++++++++++++++-----
src/runtime/nitro/plugins/50-updateCsp.ts | 6 +++++
src/utils/island.ts | 5 ++++
3 files changed, 33 insertions(+), 7 deletions(-)
create mode 100644 src/utils/island.ts
diff --git a/src/runtime/nitro/plugins/40-cspSsrNonce.ts b/src/runtime/nitro/plugins/40-cspSsrNonce.ts
index ba97c305..2bb1a7f2 100644
--- a/src/runtime/nitro/plugins/40-cspSsrNonce.ts
+++ b/src/runtime/nitro/plugins/40-cspSsrNonce.ts
@@ -1,6 +1,7 @@
import { defineNitroPlugin } from '#imports'
-import crypto from 'node:crypto'
+import { randomBytes } from 'node:crypto'
import { resolveSecurityRules } from '../context'
+import { isIslandRequst } from '../../../utils/island'
const LINK_RE = /]*?>)/gi
const SCRIPT_RE = /
\ No newline at end of file
diff --git a/playground/pages/island.vue b/playground/pages/island.vue
new file mode 100644
index 00000000..9f18b75e
--- /dev/null
+++ b/playground/pages/island.vue
@@ -0,0 +1,6 @@
+
+
+ Island Page
+
+
+
\ No newline at end of file
diff --git a/src/runtime/nitro/plugins/60-recombineHtml.ts b/src/runtime/nitro/plugins/60-recombineHtml.ts
index a7f4ed01..6cc082a3 100644
--- a/src/runtime/nitro/plugins/60-recombineHtml.ts
+++ b/src/runtime/nitro/plugins/60-recombineHtml.ts
@@ -24,11 +24,13 @@ export default defineNitroPlugin((nitroApp) => {
// Let's insert the CSP meta tag just after the first tag which should be the charset meta
let insertIndex = 0
- const metaCharsetMatch = html.head[0].match(/^/mdi)
- if (metaCharsetMatch && metaCharsetMatch.indices) {
- insertIndex = metaCharsetMatch.indices[0][1]
+ if (html.head.length > 0) {
+ const metaCharsetMatch = html.head[0].match(/^/mdi)
+ if (metaCharsetMatch && metaCharsetMatch.indices) {
+ insertIndex = metaCharsetMatch.indices[0][1]
+ }
+ html.head[0] = html.head[0].slice(0, insertIndex) + `` + html.head[0].slice(insertIndex)
}
- html.head[0] = html.head[0].slice(0, insertIndex) + `` + html.head[0].slice(insertIndex)
}
})
})
\ No newline at end of file
From 57ff90bc6ce8e3a3a5ac614a15d9d053805a109d Mon Sep 17 00:00:00 2001
From: Pascal Sthamer <10992664+P4sca1@users.noreply.github.com>
Date: Sat, 3 Aug 2024 13:50:55 +0200
Subject: [PATCH 7/8] Replace isIslandRequest util with check if nonce already
exist
Signed-off-by: Pascal Sthamer <10992664+P4sca1@users.noreply.github.com>
---
src/runtime/nitro/plugins/40-cspSsrNonce.ts | 5 ++---
src/utils/island.ts | 5 -----
2 files changed, 2 insertions(+), 8 deletions(-)
delete mode 100644 src/utils/island.ts
diff --git a/src/runtime/nitro/plugins/40-cspSsrNonce.ts b/src/runtime/nitro/plugins/40-cspSsrNonce.ts
index 6cf32f34..1f8f2321 100644
--- a/src/runtime/nitro/plugins/40-cspSsrNonce.ts
+++ b/src/runtime/nitro/plugins/40-cspSsrNonce.ts
@@ -1,7 +1,6 @@
import { defineNitroPlugin } from '#imports'
import { randomBytes } from 'node:crypto'
import { resolveSecurityRules } from '../context'
-import { isIslandRequest } from '../../../utils/island'
const LINK_RE = /]*?>)/gi
const SCRIPT_RE = /