Support for nonce or hash value [enhancment]
Recently I added Nuxt Security in a Project where i am fetching data from an API URL http://127.0.0.1:8000/api/blog/post/27
i am implementing Nuxt Image Module and While displaying image
<NuxtImg crossorigin="anonymous" :src="postDetail.post_image" />
It throws an error (only on Firefox, doesn't throw error on chrome and edge)
Content-Security-Policy: The page’s settings blocked the loading of a resource at inline (“script-src-attr”).
Source: this.setAttribute('data-error', 1)
which i fixed using below settings
security: {
headers: {
contentSecurityPolicy: {
'img-src': ["'self'", 'data:', 'http://127.0.0.1:8000'],
'script-src-attr': ["'unsafe-inline'"], // Added this
},
},
},
But it is considered a security risk, as it can open the door to XSS attacks. It's generally recommended to avoid using 'unsafe-inline' whenever possible. I discussed this matter with Nuxt Security and they recommend to use nonce or hash value. They also said that unfortunately Nuxt Image doesnt support nonce or hash so there is no secure way. You can find the discussion here https://github.com/Baroshem/nuxt-security/issues/218
I've created a reference implementation on the nonce propagation here https://github.com/trijpstra-fourlights/nuxt-image/tree/feat/add-nonce-support
I'll test a bit more with this and create a PR for it when it's good enough.
Hash support is not really applicable here AFAICT, as it requires computing a hash for the known script and whitelisting that in your CSP.
I am really looking forward to this feature as it would enable working well with Nuxt Image & Nuxt Security :)
Hey @pi0 could you take a look at it? It would be really useful to have this feature. Thomas is doing an amazing work in the development of Nuxt Security features and now prepared a feature for Nuxt Image that would help not only in the case of Nuxt security, but also for other projects as well :)
Yes Team Please do check and if everything looks good then proceed to merge.
@pi0
I think this issue could be closed as the PR was merged :)
I don't think that this issue is resolved fully yet. The this.setAttribute('data-error', 1) inline script is still inline onerror and results in the given error. It appears to me that the nonce is currently only added to the preload header.
Specifzing the nonce attribute on <NuxtImg> will produce the following markup:
<img onError="this.setAttribute('data-error', 1)" nonce="foo">
This will not work, even when the page specifies script-src-attr: 'nonce-foo'. It seems like nonces are not supported for inline event handlers at all. Generally, inline event handlers are considered bad practice and are hard to use with CSP.
.addEventListener() should be used instead.
Note that you only see a CSP error, when the onerror script actually gets executed, which is why some may thought that their CSP is working correctly. To test, specify an invalid image source.
Note that the error only occurs during SSR. The reason is the following line: https://github.com/nuxt/image/blob/2b6a877a9d61923d22602707a5568a3c0deb6818/src/runtime/components/nuxt-img.ts#L153
A workaround could be to attach the event listener in the onMounted hook using a ref. However, some error event may be missed in that case due to timing issues. Maybe setting the image source could be delayed until after the event listener is attached in the onMounted hook.
Looking for this support, any plans to address soon? Currently having issues when trying to implement a CSP policy:
Content-Security-Policy: The page’s settings blocked an event handler (script-src-attr) from being executed because it violates the following directive: “script-src-attr 'self'” Source: this.setAttribute('data-error', 1)
I currently experience the exact same issue, any updates on this topic?
I currently experience the exact same issue, any updates on this topic?
did you find any solution to this? i am also experiencing the exact same issue
Please refrain from "me too" posts that don't add further to the solution process. Comments notify all persons interested and take time away from contributing.
Not sure if this would work on a PR but I was able to patch the issue by making the following changes to the node_modules/@nuxt/image/dist/runtime/components/NuxtImg.vue file. I used bun patch but you could also use NPM patch-package.
<template>
<img
/* ... */
v-bind="{
/* Remove next line */
...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {},
...imgAttrs,
...attrs,
}"
:src="src"
>
<slot
/* We use the ref for this too */
ref="imgEl"
v-else
v-bind="{
imgAttrs: {
/* Remove next line */
...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {},
...imgAttrs,
...attrs,
},
isLoaded: placeholderLoaded,
src,
}"
/>
</template>
<script setup lang="ts">
/* ... */
if (isServer && imgEl.value) {
imgEl.value.addEventListener('error', () => imgEl.value?.setAttribute('data-error', '1'));
}
/* ...*/
</script>
This is my patch file for v1.9.0
# patches/@nuxt%[email protected]
diff --git a/dist/runtime/components/NuxtImg.vue b/dist/runtime/components/NuxtImg.vue
index 4625e1ef0028dd2470ed832106cea08e9adcac38..8f6ae6df24766e40b33a65977e0c2313e99a1f9b 100644
--- a/dist/runtime/components/NuxtImg.vue
+++ b/dist/runtime/components/NuxtImg.vue
@@ -4,7 +4,6 @@
ref="imgEl"
:class="props.placeholder && !placeholderLoaded ? props.placeholderClass : undefined"
v-bind="{
- ...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {},
...imgAttrs,
...attrs,
}"
@@ -12,8 +11,8 @@
>
<slot
v-else
+ ref="imgEl"
v-bind="{
- ...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {},
imgAttrs: {
...imgAttrs,
...attrs,
@@ -118,6 +117,9 @@ const mainSrc = computed(() =>
const src = computed(() => placeholder.value ? placeholder.value : mainSrc.value)
+if(import.meta.server && imgEl.value) {
+ imgEl.value.addEventListener('error', () => imgEl.value?.setAttribute('data-error', '1'))
+}
if (import.meta.server && props.preload) {
const isResponsive = Object.values(sizes.value).every(v => v)
Not sure if this would work on a PR but I was able to patch the issue by making the following changes to the
node_modules/@nuxt/image/dist/runtime/components/NuxtImg.vuefile. I usedbun patchbut you could also use NPM patch-package.![]()
This is my patch file for v1.9.0
patches/@nuxt%[email protected]
diff --git a/dist/runtime/components/NuxtImg.vue b/dist/runtime/components/NuxtImg.vue index 4625e1ef0028dd2470ed832106cea08e9adcac38..8f6ae6df24766e40b33a65977e0c2313e99a1f9b 100644 --- a/dist/runtime/components/NuxtImg.vue +++ b/dist/runtime/components/NuxtImg.vue @@ -4,7 +4,6 @@ ref="imgEl" :class="props.placeholder && !placeholderLoaded ? props.placeholderClass : undefined" v-bind="{
}" @@ -12,8 +11,8 @@...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {}, ...imgAttrs, ...attrs,<slot v-else
- ref="imgEl" v-bind="{
...isServer ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {}, imgAttrs: { ...imgAttrs, ...attrs,@@ -118,6 +117,9 @@ const mainSrc = computed(() =>
const src = computed(() => placeholder.value ? placeholder.value : mainSrc.value)
+if(import.meta.server && imgEl.value) {
- imgEl.value.addEventListener('error', () => imgEl.value?.setAttribute('data-error', '1')) +} if (import.meta.server && props.preload) { const isResponsive = Object.values(sizes.value).every(v => v)
I dont see any open PRs for this, worth opening i think?