next.js: Inline styles in Next 10 don't work with strict Content-Security-Policy
Bug report
Describe the bug
Recent versions of Next are using inline styles, which break our apps because we block style-src: unsafe-inline
in our Content-Security-Policy
header. In fact, the default behaviour of any CSP is to block unsafe inline styles. While the risk may be less than with unsafe inline scripts, there is still a risk: see this StackOverflow answer.
We have extremely high security requirements at my company so it’s not really a matter of easily being able to disable unsafe-inline
, and I’m aware that the future intention is to move more of the styling inline. If we can’t upgrade Next because of this, we’ll either be stuck on an old version and potentially vulnerable that way, or we’ll have to consider alternatives (which I really don’t want to do!).
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Create a
Content-Security-Policy
header innext.config.js
withstyle-src: 'self';
(i.e. withoutunsafe-inline
explicitly enabled) - Run the app in production mode
- See error in console:
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self'". Either the 'unsafe-inline' keyword, a hash, or a nonce ('nonce-...') is required to enable inline execution.
Expected behavior
If inline styles can’t be disabled, there should be the ability to add a nonce. This nonce will need to be regenerated on every request, and be able to be injected into the content-security-policy header.
I can see that the Head
component in next/document
accepts a nonce
prop but this doesn’t appear to apply to Next-generated inline styles. Additionally, when trying to set the nonce
prop I found it was being set on the link
elements as a blank attribute - the actual nonce value was not being passed in, despite it being present in this.props.nonce
(I tested with some console.logging in the compiled Next code).
System information
- Version of Next.js: [e.g. 6.0.2] 10.0.0
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 18
- Comments: 18 (9 by maintainers)
Commits related to this issue
- Add "nonce" from <Head> to the injected <style> to satisfy CSP (#19150) Fixes #18557 — committed to vercel/next.js by styfle 4 years ago
- Fix CSP for using next/image https://github.com/vercel/next.js/issues/18557#issuecomment-727161142 — committed to miya-start/next-chat by miya-start 3 years ago
- add unsafe inline to style-src no good solution to implement nonce and hash exists current https://github.com/styled-components/styled-components/issues/2363 https://github.com/vercel/next.js/issue... — committed to ente-io/photos-web by abhinavkgrd 3 years ago
I’m looking into this problem at the moment and I get the feeling that the solution is not appropriate. I don’t consider myself an expert on this, so please correct me if I’m wrong. So here’s the problem:
For a solution based on nonce it is essential that the value is randomly generated for every single request.
This means:
render()
method of_document
, does not work for statically rendered HTML pages as the nonce value will be generated once at build time and then remains the same until it is built again.If I’m not missing anything here, this pretty much defeats one of the main objectives of Next.js, which is to make page loads as fast as possible.
As I said earlier today here, I don’t know the background of why the way CSS is now being loaded/pre-loaded has been changed recently. From what I can tell, everything worked fine until at least version 9.4, without the need for
fetch
-ing CSS and injecting styles.Tiny speed improvements should not stand above best-practice security measures. Like I said, I don’t know the background is, but I think more needs to be done here. At the moment, if I want to stay on version 10, I have no choice but to use a
style-src: 'unsafe-inline'
CSP.I don’t think the OP’s issue has been fixed here… next/image still outputs inline styles which means that you still have to use unsafe-inline for style-src
@Timer does Styled-JSX support
nonce-
stuff? I still get warnings with this apporach (withoutunsafe-inline
), most probably caused by Styled-JSX.The solutions proposed seem to work with the scripts injected by next, also with Material-UI, but I’m using CSS Modules, and none of my style tags have the nonce (next v11):
@sophiekoonin While we’re working on official (fully managed) CSP control within Next.js itself, we fixed the ability for you to pass
nonce
to<Head>
in_document
and have Next.js use it!This should allow you to generate a valid CSP. You probably need to move from a
headers
approach to a<meta />
tag though if possible (so you can randomize it each request).This doesn’t work with material-ui because the
style
tag doesn’t have the nonce. Any idea on how to add it?The Next.js example with material-ui injects the styles in _document.js like follows:
You’re right @Manc, as Lukas Weichselbaum from web.dev said in a recent post, nonce-based CSP only works if the number is not guessable and newly generated at runtime for every response.
That’s why I’ve come to build the next-strict-csp package on NPM to implement a hash-based CSP with Next.js the right way.
Enjoy!
Something along these lines, copying the above code:
@sophiekoonin it’s not blank, just not visible to you via dev tools (see this answer on SO: https://stackoverflow.com/a/55673767/5805244).
Looks like the issue was solved and merged a couple weeks before this comment: https://github.com/vercel/next.js/pull/19150
nonce attribute is pulled from the
head
tag and applied to style tags that are later generated and inserted.@Timer This is great news! Is there an RFC or an issue I could subscribe to for updates?