Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content-Security-Policy: The page’s settings blocked the loading of a resource at inline #218

Closed
rahul37865 opened this issue Sep 26, 2023 · 8 comments · Fixed by #212
Closed
Labels
question Further information is requested

Comments

@rahul37865
Copy link

rahul37865 commented Sep 26, 2023

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
While displaying image it throws error
Content-Security-Policy: The page’s settings blocked the loading of a resource at http://127.0.0.1:8000/api/blog/post_image/img12.jpg (“img-src”).
Which i fixed using below settings

  security: {
    headers: {
      contentSecurityPolicy: {
        'img-src': ["'self'", 'data:', 'http://127.0.0.1:8000'],     // This line fixed it
      },
      strictTransportSecurity: 'max-age=0;'
    },
  },

and adding crossorigin="anonymous" in img tag <img crossorigin="anonymous" :src="postDetail.post_image" />
This fixed the issue but now i am implementing Nuxt Image Module and when i write
<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
    },
    strictTransportSecurity: 'max-age=0;'
  },
},

My concern is, 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.
Is there any other secure way to fix this error ?

@rahul37865 rahul37865 added the question Further information is requested label Sep 26, 2023
@Baroshem
Copy link
Owner

Hey

Yes, the safer solution would be to use nonce like following

https://nuxt-security.vercel.app/security/headers#nonce-support

@rahul37865
Copy link
Author

I am not sure if i am using this in a correct way I changed setting as below

security: {
  headers: {
    contentSecurityPolicy: {
      'img-src': ["'self'", 'data:', 'http://127.0.0.1:8000'],
      'script-src-attr': [ "'self'", "'nonce-{{nonce}}'","'strict-dynamic'" ]
    },
    strictTransportSecurity: 'max-age=0;'
  },
},

Then i used useNonce() composable to get valid nonce then injected it as below

<script setup>
    const nonce = useNonce()
</script>
<template>
    <NuxtImg :nonce="nonce" crossorigin="anonymous" :src="postDetail.post_image" />
</template>

It doesn't resolve the error which i mentioned previously

Content-Security-Policy: The page’s settings blocked the loading of a resource at inline (“script-src-attr”).
Source: this.setAttribute('data-error', 1)

after making change it is also showing 3 warnings as below

Content-Security-Policy: Couldn’t parse invalid host 'nonce-{{nonce}}'
Content-Security-Policy: Ignoring “'self'” within script-src-attr: ‘strict-dynamic’ specified
Content-Security-Policy: Keyword ‘strict-dynamic’ within “script-src-attr” with no valid nonce or hash might block all scripts from loading

@Baroshem
Copy link
Owner

Hmm interesting.

@trijpstra-fourlights would you be up for helping with that? You have proven to be an expert in this area 😉

@trijpstra-fourlights
Copy link
Contributor

trijpstra-fourlights commented Sep 27, 2023

Pfew, a couple of things going wrong here so I'll try to explain what I think is happening!


First, an explanation on nonce:

By design, the nonce attribute is unique for every request. The middleware will regenerate the nonce and inject it in the headers.

If you are talking to an API endpoint served by your nuxt instance (e.g. /api/image/xyz), that means that without additional configuration the nonce attribute on that request will differ from the originating page, resulting in a CORS violation.

This extra configuration is (sparsely) described int he documentation

relevant part (you would want the mode: check on the relevant API URIs):

image


However, looking at your OP, it seems that the API is actually served under a different URI (i.e. not by nuxt). That's why you need to add the specific URI to the img-src allowed list. The crossorigin='anonymous' makes sure that no cookies are sent when requesting this URI. Without this, the API would be required to set the nuxt URL as an allowed origin, otherwise you'll get CSP violations again.

So, assuming that the image is served by a different service, adding nonce makes no sense as the nonce value is not known by the API.

That leaves us only with the initial error which occurs when using NuxtImg

Content-Security-Policy: The page’s settings blocked the loading of a resource at inline (“script-src-attr”).
Source: this.setAttribute('data-error', 1)

Unfortunately, this is due to how NuxtImg works internally. They are setting attribute at runtime (i.e. inline) which requires you to explicitly allow that in your CSP.

Normally, your options for this are:

  1. adding unsafe-inline to script-scr-attr (which, as you already said, opens up a security hole)
  2. 'whitelisting' NuxtImg to be able to do this (with nonce-)

However, NuxtImg does not currently support receiving (and propagating) a nonce value. Thus you are (if you want to use NuxtImg and enforce a strict CSP) limited to option 1 with all its potential security downsides.

So, as far as I can tell, the fix for this is that someone implements nonce awareness in NuxtImg (i.e. NuxtImg understands the nonce prop and propagates it to the actual injected html tags).


Lastly, while it makes no sense to add the nonce (as explained above), the actual error your seeing in #218 (comment) is due to you not enabling nonce in the security settings. If you would have added nonce: true to the security config the error would've disappeared (but it would still not have worked due to NuxtImage not understanding a nonce property.


edit (1): fix formatting
edit (2): removed hash propagation as a possible solution as it's not applicable in this case because it requires computing a hash of the offending resource and whitelisting that explicitly in your CSP config

@rahul37865
Copy link
Author

Thanks @trijpstra-fourlights for this comprehensive explanation I raised the issue on Nuxt/Image I hope they will come up with a solution.

@trijpstra-fourlights
Copy link
Contributor

trijpstra-fourlights commented Sep 27, 2023

No problem.

I've taken a stab at the nonce implementation for @nuxt/image and I think it works.
You could try to use it directly, the PR branch is: https://github.com/trijpstra-fourlights/nuxt-image/tree/feat/add-nonce-support-rebased

For reference, this is the nuxt-security config I tested it with:

  security: {
    nonce: true,
    headers: {
      contentSecurityPolicy: {
        'img-src': ["'self'", 'data:', 'https:'],
        'style-src': ["'self'", "'nonce-{{nonce}}'"],
        'script-src': [
          "'self'", // backwards compatibility for older browsers that don't support strict-dynamic
          "'nonce-{{nonce}}'",
          "'strict-dynamic'"
        ],
        'script-src-attr': ["'self'", "'nonce-{{nonce}}'", "'strict-dynamic'"]
      }
    }
  }
<template>
  <NuxtImg src="https://localhost:8000/api/image/xyz" :nonce="nonce" />
</template>

<script lang="ts" setup>
const nonce = useNonce()
</script>

@Baroshem
Copy link
Owner

Great man @trijpstra-fourlights ! 🚀

Thank you so much. I am looking forward to the development of this issue / feature request :)

@Baroshem
Copy link
Owner

I have added the documentation about it 2f12bd6. Once it will be merged to NuxtImage I will deploy Nuxt Security docs with this instructions :)

@Baroshem Baroshem mentioned this issue Sep 29, 2023
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants