-
-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Description
Documentation is
- Missing
- Outdated
- Confusing
- Not sure?
Explain in Detail
Update:
Thanks to the clarification from @sapphi-red, I now have a better understanding of the intended mechanism. My initial report had some incorrect assumptions:
- I now understand the
<meta property="csp-nonce">
is for Vite's internal use, not for setting the policy itself. - I also understand that
html.cspNonce
should be set to a literal placeholder string (e.g.,'CSP_NONCE_PLACEHOLDER'
), not a randomly generated value withinvite.config.js
. This is correctly documented.
My core concern remains, however, that the documentation doesn't adequately guide the user on how to implement the required server-side replacement, especially in common deployment scenarios like SPAs, where it might interfere with caching. I've detailed this in my follow-up comment below, suggesting that maybe the docs should point to hash-based CSP as a better solution for the typical Vite user.
Original:
Hey there,
First off, thank you for building and maintaining Vite!
As documented elsewhere, notably here and here, there might be some amount of perceived "security theater" on Vite's documentation regarding the Content Security Policy (CSP) info mentioned prominently on the "Features" page:
Content Security Policy (CSP)
To deploy CSP, certain directives or configs must be set due to Vite's internals.
'nonce-{RANDOM}'
When
html.cspNonce
is set, Vite adds a nonce attribute with the specified value to any<script>
and<style>
tags, as well as<link>
tags for stylesheets and module preloading. Additionally, when this option is set, Vite will inject a meta tag (<meta property="csp-nonce" nonce="PLACEHOLDER" />
).The nonce value of a meta tag with
property="csp-nonce"
will be used by Vite whenever necessary during both dev and after build.WARNING: Ensure that you replace the placeholder with a unique value for each request. This is important to prevent bypassing a resource's policy, which can otherwise be easily done.
First of, a bit of a CSP 101:
- Basically, CSP is a set of security measures in which the server should send, for all resource URIs, a
Content-Security-Policy
header, containing some restrictions for the user argent to follow, regarding from which origins or URIs the user agent can load resources.- It helps mitigate attacks like Cross-Site Scripting (XSS)
- Examples:
Content-Security-Policy: default-src 'self'; img-src 'self' https://example.com;
- The keyword
default-src
defines the basic policy, which can then be tuned for particular resource types, such asscript-src
. - The value
self
limits new resources to those with the same origin. - Typically, you would enable 'self', plus trusted origins such as CDNs.
- Also, the
nonce
mechanism is used to limit execution of inline scripts to those for which a correspondingnonce
attribute is present on the script tag.- As the name implies, each response should contain an unique nonce.
- Example:
<!-- Content-Security-Policy: script-src 'self' 'nonce-abc123'; --> <script nonce="abc123">console.log("Hello, world!");</script> <script>console.log("This will not run!");</script>
- The CSP information could be provided on a
<meta>
tag, but this is considered less secure than on the HTTP Header. (source)
Back to html.cspNonce
Now, the issues I find when trying to implement this feature are the following:
- The
meta
tag is not the right way to implement this. It should be done with aContent-Security-Policy
HTTP header if possible (source) - If you generate a random
nonce
both for the header and for thehtml.cspNonce
option, on thevite.config.js
, Vite would read this file twice at different times to generate one or the other, entirely breaking your site by not having a matching nonce everywhere. - Even worse, if you build a SPA with
vite build
, thenonce
will be generated only once, which is not secure at all, as it should be different for every request. Not to mention thatnonce
is not compatible with static content which is usually cached. - Some partial measures exist, such as the plugin
vite-plugin-csp-guard
, but it notoriously documents that it doesn't generate a nonce for SPAs (source), rather relying on "hash-based CSP."
This discovery process can be frustrating and time-consuming. More importantly, a developer might miss the nuance and deploy a statically-generated nonce
, creating a false sense of security. The fact that this is a known point of confusion is validated by existing issues linked above.
Your Suggestion for Changes
I propose that the documentation for the html.cspNonce
option be updated to explicitly state its limitations and current recomended usage (if any). Adding a prominent warning or tip would be incredibly effective.
Thank you again for your time and for all your hard work on Vite.
Reproduction
No response
Steps to reproduce
No response