cristianbote / goober

🥜 goober, a less than 1KB 🎉 css-in-js alternative with a familiar API
https://goober.rocks
MIT License
3.13k stars 118 forks source link

CSP Nonce #471

Open jd-carroll opened 2 years ago

jd-carroll commented 2 years ago

We have a pretty strict CSP-Policy for our site and we would like to use a library which consumes goober. The problem is that goober will inject styles directly to the document and if you have a CSP with pretty much anything other than 'unsafe-inline' the browser will reject the insertion with an error that looks like:

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'nonce-xz5NmxIucN9byPuojlWd4'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.

I don't pretend to know every that would need to be implemented to solve this issue (and certainly not the consequences for making them).

However, I can say with certainty that the issue is this chunk of code: https://github.com/cristianbote/goober/blob/0f74be5079e01916158198d74c8e5872fa7b518c/src/core/get-sheet.js#L17-L20

            Object.assign((target || document.head).appendChild(document.createElement('style')), {
                innerHTML: ' ',
                id: GOOBER_ID
            })

At the very least the createElement would need to be changed to:

  document.createElement('style', { nonce })

The next question will be where does the nonce come from, which there could be several answers.

But before we get there, I'd like to do a quick reality check... Would this be a series of changes goober is open / willing to make?

We are at an impasse right now with the library we want to use (it must be pulled out). So there are two options we can pursue:

  1. Get a change implemented in goober and then work the library author to consume that change
  2. Just go a different direction (implement a different library)

What are people's thoughts?

jd-carroll commented 2 years ago

I opened the issue above because I think it is a valid conversation, but there is a work around.

The saving grace is that goober looks for a target container and if it doesn't find one, then it will create one. The saving grace is that it also generically looks at the window object for any id. This part: https://github.com/cristianbote/goober/blob/0f74be5079e01916158198d74c8e5872fa7b518c/src/core/get-sheet.js#L16

What this means is if you're using React (in my case NextJS), you can do something like the following:

In your _document.tsx add the following element to your head:

          <style
            nonce={nonce}
            id='_goober'
          />

This way, instead of goober creating a new element, it will reuse one that already exists. And it also happens to have the nonce already. 🌈 🍯

cristianbote commented 2 years ago

Heya @jd-carroll if this is strictly related to NextJS than yeah it's kinda needed to have the style element already defined. Check out the main example: https://github.com/vercel/next.js/blob/canary/examples/with-goober/pages/_document.js

longsleep commented 11 months ago

I don't see how defining a