nuxt
nuxt copied to clipboard
CSP support
Nuxt 2 implementation:
- https://github.com/nuxt/nuxt.js/blob/dev/packages/server/src/middleware/nuxt.js#L130
- (also fragmentations in several places)
I guess we can try making an standard unjs package and use in nitro server + allow a pluggable approach for both middleware and app to declare other scripts to be included in CSP policy
Upstream: https://github.com/unjs/h3/issues/336
Would be great if the nuxt3 CSP implementation could support csp3 strict-dynamic (https://github.com/nuxt/nuxt.js/issues/7451) and automatically generate a csp nonce on every request that is easily accessible (https://github.com/nuxt/nuxt.js/issues/6811).
Hey folks,
For anyone contributing to this issue. In my security module for nuxt there is a CSP configuration available. Let me know if you have some recommendations so that I could implement them as a part of the module :)
Team, two years from when this issue was created, do we have a solution in place? The security module mentioned in some of the comments uses "unsafe-inline", so is definitely not a secure option. Even if we do not have an end-to-end solution, is there at least a way to ensure that all script tags are added dynamically so that we can layer a custom solution on top of that by, for example, manually calculating hashes?
Actually, there's some (albeit slow) progress on the vite side of things https://github.com/vitejs/vite/pull/11864 which is quite important especially for the CSS part of it all
@Tristan971 Had a quick look and it seems to be focused on the use of a nonce, which doesn't work for us, since we don't do SSR.
I fully understand your predicament, as we do CSR too here.
The problem is that you CAN already compute chunk files hashes during the build now, and then edit the rendered HTML via Nitro hooks during serving. But most of the work going on in your app happens via JS in vite's applyStyles etc functions, and that isn't transitively trusted as far as I can tell, even with strict-dynamic.
For now I'm waiting to see what happens when vite has a solution at all, which will almost certainly be nonce-based, and then we can see if it's adaptable somehow to hashes, but I wouldn't hold my breath for it.
Alas, CSP support isn't in extremely high demand (or rather, we are all probably a bit too polite for our own good when asking for it), so we'll take what we can get until someone invests their own time in making things move forward. Even if that means years of security compromises...
Thanks @Tristan971. I'm not very hopeful that the nonce-based approach would work for hashes. If my understanding is correct, strict-dynamic
allows script
tags with a src
attribute if they have the right nonce, but it doesn't allow that for hashes.
Looks like you've dabbled with vite and understand some of its inner workings. Where would be the best place for me to start if I wanted to customise the way those tags are rendered? I know you mentioned Nitro hooks, but have you come across any specific guides?
You could check out how nuxt-security
adds nonces and adapt that for hashes: https://github.com/Baroshem/nuxt-security/blob/0d36fec295e9b8bb2d5749d3330ff88397fe8ac6/src/runtime/nitro/plugins/99-cspNonce.ts#L25
When I dabbled in that area, adding nonces like that wasn't enough (took a very similar approach at the time), due to the way styles are dynamically applied by Vite, but maybe I missed something back then.
Probably worth another look, or waiting for vite... will see
Wanted to come back here and update everyone with my findings so far. I was planning to start looking at Nitro hooks to replace script tags with one that adds all libraries dynamically. I was also planning to look at Vite to see if there is a way to calculate hashes during build time and inject the output into the config that will drive the CSP header.
However, while I was doing the preparation work for this, I found out that none of it is necessary! Without listing any hashes in my CSP, I could use 'strict-dynamic'
in the script-src
directive and it just works. Nuxt must be really doing something right to make this work out of the box!
The only change I had to do was remove a script that was being inserted using app.head
in nuxt.config.ts
and replace that with a dynamic script using useHead
where I declare the innerHTML
attribte of the script
as a string containing a script that dynamically adds a script
element for each of the scripts I need, as described in the article I linked to earlier.
script: [
{
innerHTML: `var scripts = [ 'some-library.js', 'another-library-url.js' ];
scripts.forEach(function(scriptUrl) {
var s = document.createElement('script');
s.src = scriptUrl;
s.async = false;
document.head.appendChild(s);
});`
}
]
I must say I'm quite surprised by this behaviour, given that when I put my CSP into the csp-evaluator
tool, it basically says that strict-dynamic
without hashes will block all scripts, but I tested it and our code is working just fine. I will continue to test and update here with any further findings.
Just a quick update that the behaviour I described above changed as soon as I started deploying to the actual environments (i.e. not locally). Unsurprisingly, I had to add a hash for the main block of JS code generated by Nuxt, but only one hash so far.
Given I still need to specify at least one hash in my CSP, I would like to find a way to calculate that hash at build time so that I can use it in a later step in the build process to inject it into the configuration that will drive the CSP header. I looked at the approach used in nuxt-security
as suggested by @dargmuesli but that is using Nitro hooks, which are runtime. According to the docs, I should be using a Nuxt hook, which is build time. I experimented with several hooks, but I cannot find any that is called after pre-rendering and that will give me access to the pre-rendered assets. Does anyone have any pointers or can suggest alternate approaches?
Yes, the Nuxt hook nitro:build:public-assets
is likely what you want.
Yes, the Nuxt hook
nitro:build:public-assets
is likely what you want.
Thanks @danielroe. I ended up using the render:response
nitro hook. Admittedly, the code is getting a bit complicated now. One of our colleagues recently pointed out that nuxt-security
has SSG support now here. This code looks a lot like ours, except that instead of adding a meta
tag, we're using the hashes to update configuration specific to our hosting platform, which, understandably, would not be supported by the framework.
Another difference I noted is that we opted to replace all script
tags with a src
attribute with one inline script that dynamically adds the script tags to the body, whereas - without getting too deep into the code - nuxt-security
looks to be keeping the script tags and adding the integrity attribute with the hashes to them.
Yes, the Nuxt hook
nitro:build:public-assets
is likely what you want.Thanks @danielroe. I ended up using the
render:response
nitro hook. Admittedly, the code is getting a bit complicated now. One of our colleagues recently pointed out thatnuxt-security
has SSG support now here. This code looks a lot like ours, except that instead of adding ameta
tag, we're using the hashes to update configuration specific to our hosting platform, which, understandably, would not be supported by the framework. Another difference I noted is that we opted to replace allscript
tags with asrc
attribute with one inline script that dynamically adds the script tags to the body, whereas - without getting too deep into the code -nuxt-security
looks to be keeping the script tags and adding the integrity attribute with the hashes to them.
@tnabil Does it support CSP for SPA mode ? or Is there a way for that?
Sorry, I only looked quickly at the code but never actually tested the next-security implementation, as we’re currently using our own custom implementation.
On Mon, 1 Jul 2024 at 5:25 PM, Adem Yalçın @.***> wrote:
Yes, the Nuxt hook nitro:build:public-assets is likely what you want.
Thanks @danielroe https://github.com/danielroe. I ended up using the render:response nitro hook. Admittedly, the code is getting a bit complicated now. One of our colleagues recently pointed out that nuxt-security has SSG support now here https://github.com/Baroshem/nuxt-security/blob/0d36fec295e9b8bb2d5749d3330ff88397fe8ac6/src/runtime/nitro/plugins/02-cspSsg.ts. This code looks a lot like ours, except that instead of adding a meta tag, we're using the hashes to update configuration specific to our hosting platform, which, understandably, would not be supported by the framework. Another difference I noted is that we opted to replace all script tags with a src attribute with one inline script that dynamically adds the script tags to the body, whereas - without getting too deep into the code - nuxt-security looks to be keeping the script tags and adding the integrity attribute with the hashes to them.
@tnabil https://github.com/tnabil Does it support CSP for SPA mode ? or Is there a way for that?
— Reply to this email directly, view it on GitHub https://github.com/nuxt/nuxt/issues/11793#issuecomment-2200301440, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAVEQWL5CSVR2VZRSLLAWSTZKFRDZAVCNFSM6AAAAABKFWHUOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMBQGMYDCNBUGA . You are receiving this because you were mentioned.Message ID: @.***>
Sorry, I only looked quickly at the code but never actually tested the next-security implementation, as we’re currently using our own custom implementation. … On Mon, 1 Jul 2024 at 5:25 PM, Adem Yalçın @.> wrote: Yes, the Nuxt hook nitro:build:public-assets is likely what you want. Thanks @danielroe https://github.com/danielroe. I ended up using the render:response nitro hook. Admittedly, the code is getting a bit complicated now. One of our colleagues recently pointed out that nuxt-security has SSG support now here https://github.com/Baroshem/nuxt-security/blob/0d36fec295e9b8bb2d5749d3330ff88397fe8ac6/src/runtime/nitro/plugins/02-cspSsg.ts. This code looks a lot like ours, except that instead of adding a meta tag, we're using the hashes to update configuration specific to our hosting platform, which, understandably, would not be supported by the framework. Another difference I noted is that we opted to replace all script tags with a src attribute with one inline script that dynamically adds the script tags to the body, whereas - without getting too deep into the code - nuxt-security looks to be keeping the script tags and adding the integrity attribute with the hashes to them. @tnabil https://github.com/tnabil Does it support CSP for SPA mode ? or Is there a way for that? — Reply to this email directly, view it on GitHub <#11793 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAVEQWL5CSVR2VZRSLLAWSTZKFRDZAVCNFSM6AAAAABKFWHUOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMBQGMYDCNBUGA . You are receiving this because you were mentioned.Message ID: @.>
Do you use SPA mode? and also do you have a chance to share your implementation in any case?
Yes, we run in SPA mode. Unfortunately, I cannot share the code.
On Thu, 11 Jul 2024 at 4:54 PM, Adem Yalçın @.***> wrote:
Sorry, I only looked quickly at the code but never actually tested the next-security implementation, as we’re currently using our own custom implementation. … <#m_9210721131465155778_> On Mon, 1 Jul 2024 at 5:25 PM, Adem Yalçın @.> wrote: Yes, the Nuxt hook nitro:build:public-assets is likely what you want. Thanks @danielroe https://github.com/danielroe https://github.com/danielroe https://github.com/danielroe. I ended up using the render:response nitro hook. Admittedly, the code is getting a bit complicated now. One of our colleagues recently pointed out that nuxt-security has SSG support now here https://github.com/Baroshem/nuxt-security/blob/0d36fec295e9b8bb2d5749d3330ff88397fe8ac6/src/runtime/nitro/plugins/02-cspSsg.ts https://github.com/Baroshem/nuxt-security/blob/0d36fec295e9b8bb2d5749d3330ff88397fe8ac6/src/runtime/nitro/plugins/02-cspSsg.ts. This code looks a lot like ours, except that instead of adding a meta tag, we're using the hashes to update configuration specific to our hosting platform, which, understandably, would not be supported by the framework. Another difference I noted is that we opted to replace all script tags with a src attribute with one inline script that dynamically adds the script tags to the body, whereas - without getting too deep into the code - nuxt-security looks to be keeping the script tags and adding the integrity attribute with the hashes to them. @tnabil https://github.com/tnabil https://github.com/tnabil https://github.com/tnabil Does it support CSP for SPA mode ? or Is there a way for that? — Reply to this email directly, view it on GitHub <#11793 (comment) https://github.com/nuxt/nuxt/issues/11793#issuecomment-2200301440>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAVEQWL5CSVR2VZRSLLAWSTZKFRDZAVCNFSM6AAAAABKFWHUOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMBQGMYDCNBUGA https://github.com/notifications/unsubscribe-auth/AAVEQWL5CSVR2VZRSLLAWSTZKFRDZAVCNFSM6AAAAABKFWHUOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMBQGMYDCNBUGA . You are receiving this because you were mentioned.Message ID: @.>
Do you use SPA mode? and also do you have a chance to share your implementation in any case?
— Reply to this email directly, view it on GitHub https://github.com/nuxt/nuxt/issues/11793#issuecomment-2223003794, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAVEQWLCF27PKRAIW6DJA7LZL2FBPAVCNFSM6AAAAABKFWHUOCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRTGAYDGNZZGQ . You are receiving this because you were mentioned.Message ID: @.***>