-
Notifications
You must be signed in to change notification settings - Fork 26k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inline styles in Next 10 don't work with strict Content-Security-Policy #18557
Comments
@sophiekoonin While we're working on official (fully managed) CSP control within Next.js itself, we fixed the ability for you to pass This should allow you to generate a valid CSP. You probably need to move from a |
@Timer This is great news! Is there an RFC or an issue I could subscribe to for updates? |
@paambaati you can use the following approach right now: import NextDocument, {Html, Head, Main, NextScript} from "next/document"
let prod = process.env.NODE_ENV == "production"
let csp = ``
csp += `base-uri 'self';`
csp += `form-action 'self';`
csp += `default-src 'self';`
csp += `script-src 'self' ${prod ? "" : "'unsafe-eval'"};` // NextJS requires 'unsafe-eval' in dev (faster source maps)
csp += `style-src 'self' https://fonts.googleapis.com 'unsafe-inline' data:;` // NextJS requires 'unsafe-inline'
csp += `img-src 'self' https://*.githubusercontent.com https://paqmind.imfast.io data: blob:;`
csp += `font-src 'self' https://fonts.gstatic.com;` // TODO
csp += `frame-src *;` // TODO
csp += `media-src *;` // TODO
// require-trusted-types-for 'script';" TODO
let referrer = "strict-origin"
export default class Document extends NextDocument {
render () {
return <Html prefix="og: http://ogp.me/ns#" lang="ru">
<Head>
<meta httpEquiv="Content-Security-Policy" content={csp}/>
<meta name="referrer" content={referrer}/>
</Head>
<body>
<Main/>
<div id="modal"/>
<NextScript/>
</body>
</Html>
}
} You'll need to replace my static domains, etc. with yours obviously. I kept mine for extra context. As @Timer mentioned, one the latest NextJS releases also removes the need for |
Something along these lines, copying the above code: import NextDocument, { Html, Head, Main, NextScript } from "next/document";
import { randomBytes } from "crypto";
let prod = process.env.NODE_ENV == "production";
function getCsp(nonce) {
let csp = ``;
csp += `base-uri 'self';`;
csp += `form-action 'self';`;
csp += `default-src 'self';`;
csp += `script-src 'self' ${prod ? "" : "'unsafe-eval'"};`; // NextJS requires 'unsafe-eval' in dev (faster source maps)
csp += `style-src 'self' https://fonts.googleapis.com 'nonce-${nonce}' data:;`; // NextJS requires 'unsafe-inline'
csp += `img-src 'self' https://*.githubusercontent.com https://paqmind.imfast.io data: blob:;`;
csp += `font-src 'self' https://fonts.gstatic.com;`; // TODO
csp += `frame-src *;`; // TODO
csp += `media-src *;`; // TODO
return csp;
}
// require-trusted-types-for 'script';" TODO
let referrer = "strict-origin";
export default class Document extends NextDocument {
render() {
// Regenerated every render:
const nonce = crypto.randomBytes(8).toString("base64");
return (
<Html prefix="og: http://ogp.me/ns#" lang="ru">
<Head nonce={nonce}>
<meta httpEquiv="Content-Security-Policy" content={getCsp(nonce)} />
<meta name="referrer" content={referrer} />
</Head>
<body>
<Main />
<div id="modal" />
<NextScript />
</body>
</Html>
);
}
} |
@Timer does Styled-JSX support |
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 |
Looks like the issue was solved and merged a couple weeks before this comment: #19150 nonce attribute is pulled from the |
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:
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 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 |
This doesn't work with material-ui because the The Next.js example with material-ui injects the styles in _document.js like follows:
|
@sophiekoonin it's not blank, just not visible to you via dev tools (see this answer on SO: https://stackoverflow.com/a/55673767/5805244). |
I tried the above solution and it works great, as it blocks the scripts which are not whitelisted by a nonce. However for some reason the Content Security Policy header does not show up on the response headers during HTTP request. Is that normal behaviour or did I miss something? PS I am using a custom Express server, but was unable to get the CSP working with Helmet as I was unable to get req.locales (req returns undefined in _document.js). Hence I think the above solution should work for now? |
@BleddP I think they don't show in the http header because they're set in
|
Yeah, as @mcha-dev said. Some security analizers don't check for meta tags but that's an issue with those services. I even personally asked 1 or 2 of them to fix their algorithms and it was done. According to standards, meta and headers are interchangeable for this particular piece of data. |
This is because the meta tag and HTTP headers are two different approaches for the same result. Nevertheless, it is still recommended to go for the headers one as they provide more features. Reference: https://content-security-policy.com/examples/meta/ |
This is mostly working for me, in that I can see that nonces are being added to every script and inline style that is being injected by Next which is great. However, I've found that a few Next components add style attributes. In particular the The best solution I've found is to write a csp like this
So that in modern browsers that support Does anyone else have a better workaround for this? Or would it be possible for Next to stop using style attributes? |
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! |
no good solution to implement nonce and hash exists current styled-components/styled-components#2363 vercel/next.js#18557 (comment)
This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
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 ourContent-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:
Content-Security-Policy
header innext.config.js
withstyle-src: 'self';
(i.e. withoutunsafe-inline
explicitly enabled)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 innext/document
accepts anonce
prop but this doesn't appear to apply to Next-generated inline styles. Additionally, when trying to set thenonce
prop I found it was being set on thelink
elements as a blank attribute - the actual nonce value was not being passed in, despite it being present inthis.props.nonce
(I tested with some console.logging in the compiled Next code).System information
The text was updated successfully, but these errors were encountered: