-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Content Security Policy (CSP) with next.js #256
Comments
I'm not familiar with CSP, but it seems next.js doesn't support CSP at all for now. |
CSP is kind a standard for web security and usually we disable eval with CSP. (and similar functionalities) That's being said, stored XSS is not possible with React unless you use So, we are not in a huge security risk. |
@dbo about this:
I hope this is about another issue. |
@arunoda IMHO this is a blocker to seriously deploy next.js apps; CSP is a standard, eval discouraged. Avoiding Regarding your latter question: I think this task should be about getting next.js running with strict CSP, i.e. preferably the hashes for the inline script as well as a SRI hash for the CDN-script could be generated (at build time?), so no need to allow any inline-script, CDN script-src. |
@dbo just so I understand the attack surface better: why would you use a template engine in this context? |
As I've written, my primary code can (and should) avoid Also look at this from a different angle: Any serious customer would require you to do a security audit/proof of the site you've built. Given a decent browser baseline, it's much easier and less effort to do that in context of a CSP. |
Definitely. I'll keep this open. Consider this approach: The problem is that it introduces a new roundtrip, however. |
What you're saying is that you want a protection from yourself (unaudited code that you might include in your own codebase). That by definition is a security enhancement, not a hole. I think this is important to address, and we're thinking about how to best do it without a tradeoff in performance. |
@rauchg Of course this is not about a security hole, but a very important security enhancement, it's highly recommended and standardised practice for good reason.
to thoroughly audit all of their transitive dependencies. I simply don't expect it to happen. |
Absolutely. Was just pointing out that @nkzawa picked the right label, and On Tue, Nov 22, 2016 at 9:53 AM ǝlzlǝoq lǝᴉuɐp ツ [email protected]
|
CSP headers are definitely a high priority in my opinion. However, it's possible to use a meta tag as an alternative for the time being. https://developers.google.com/web/fundamentals/security/csp/#the_meta_tag |
@aesopwolf Using a meta tag as an alternative to HTTP headers is not the issue here, it will prevent the page from working, too, unless you allow |
@dbo my apologies, I skimmed over the thread too fast. @rauchg Is there anything we can do to help fast-lane the SRI hash for the CDN script? My company is in the final phases of a new registration app built on next.js and we expect to see 150k signups in January so having the CDN would definitely be nice to have. |
@aesopwolf as of 2.0+ there won't be a "global build" anymore, so it's not possible for us to provide a unique CDN. Each site generates its own minimal build of the framework |
@rauchg thanks for the update, that sounds like the best thing to do anyways. It moves work off zeit's end and gives developers full control of their own caching strategy 👍 |
Yeah. The goal was to provide an optimized baseline so that Next could be cached across several internet properties. But in the end, there are many slices and versions of Next across those properties, so it's a difficult endeavor. |
Update on this? |
Workaround 😂:
|
That completely defeats the purpose of CSP. |
Edit: I dug up our internal documentation on this topic and I have added some clarification, references, and corrections to my original comment The approach I've taken on projects where we want server-side rendering of React components and then client-side re-rendering (progressive rendering), where data needs to be serialized and then deserialized as part of the payload is to: Emit the data payload into a <noscript id="__NEXT_DATA__">{props:{...}, ...}</noscript> We don't just blindly use Using this approach, we serialize our store and other data from the server into these You can read the OWASP coverage of this topic here: Our approach is aligned with what they document there, but we use that extra check that there's a single element matching the ID we're looking for, and we put the data into a |
Here's what I spiked out to see if this approach would work. A modified render () {
const { staticMarkup, __NEXT_DATA__, chunks } = this.context._documentProps
const { pathname, nextExport, buildId, assetPrefix } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname, nextExport)
__NEXT_DATA__.chunks = chunks
return <div>
{staticMarkup ? null : (
<div>
<noscript id='__NEXT_DATA__' dangerouslySetInnerHTML={{ __html: htmlescape(JSON.stringify(__NEXT_DATA__)) }} />
<script type='text/javascript' src={`${assetPrefix}/static/next-script.js?${buildId}`} />
</div>
)}
<script async id={`__NEXT_PAGE__${pathname}`} type='text/javascript' src={`${assetPrefix}/_next/${buildId}/page${pagePathname}`} />
<script async id={`__NEXT_PAGE__/_error`} type='text/javascript' src={`${assetPrefix}/_next/${buildId}/page/_error/index.js`} />
{staticMarkup ? null : this.getDynamicChunks()}
{staticMarkup ? null : this.getScripts()}
</div>
} And then I had a var nextData = document.querySelectorAll('noscript#__NEXT_DATA__');
if (nextData.length === 1) {
window.__NEXT_DATA__ = JSON.parse(nextData[0].textContent);
window.module = {};
window.__NEXT_LOADED_PAGES__ = [];
window.__NEXT_LOADED_CHUNKS__ = [];
}
function __NEXT_REGISTER_PAGE(route, fn) {
__NEXT_LOADED_PAGES__.push({ route: route, fn: fn })
}
function __NEXT_REGISTER_CHUNK(chunkName, fn) {
__NEXT_LOADED_CHUNKS__.push({ chunkName: chunkName, fn: fn })
} With that in place, I added the following express middleware to my custom server: function contentSecurityPolicy(req, res, next) {
res.setHeader('Content-Security-Policy', 'script-src \'self\'');
next();
} Running the app, I get an error:
This is preventing modules from getting loaded, but I've not been able to track down what is causing this. |
Just to be clear... Is this the code that causes all the trouble? 'Cause it does not look like that needs to be 1 I get the distinct impression that I might be missing something here... 😕 |
It does look like the https://www.owasp.org/index.php/Content_Security_Policy_Cheat_Sheet#Refactoring_inline_code Instead of having After fixing that, the You can use Report-Only headers or CSP tester tools to test CSP compatibility. |
I heard from @rauchg that this issue should be resolved in the current release. Is that accurate? |
If my PR gets merged soon, CSP will be as simple as an extra line in the config file. :) |
I tested with next.js 7.0 and without adding 'unsafe-eval' to my CSP config I get:
What's the plan to not require any workaround or adding 'unsafe-eval' to the config which is definitely against CSP? |
@davidcunha Hot Module Replacement (HMR) requires eval. This is only run in dev mode and In production, this isn’t an issue. Also, my PR didn’t make it into 7.0, if you thought it did. |
Yes indeed, it's not an issue in production. I'm getting only this error while running in dev mode. |
There is some update from this PR? there would be awesome to be in the next release version. |
Hello! Any news? |
@matoous any news on what? |
Looks like you can include Content Security Policy headers in NextJS 9.5 https://nextjs.org/blog/next-9-5#headers |
This worked for me in production mode nextjs,
If you don't use We are still on [email protected] |
@OZZlE this adds I believe that: // pages/_document.js
...
<Head>
<meta httpEquiv="Content-Security-Policy" content={csp} />
</Head> is a better approach. You don't have to mess with regexp trying to detect statics. Also it's more obvious in |
@ivan-kleshnin probably you are correct but I was just handed a pre-existing project and they have multiple |
All works fine after removing the "helmet" npm package. |
For anybody else finding this issue while trying to figure out CSP stuff, I ended up building my own library to handle it. I'd encourage you all to check it out, too. |
@trezy is it possible to use your package with CSP nonce? |
@JustFly1984 not yet, no. The nonce from Next is only exposed inside the app, but |
I need a solution for CSP with nonce. Currently we found one architecture with CSP nonce , Gatsby.js and AWS API gateway, but that architecture means that we lost CDN capabilities of AWS Cloudfront. |
@ivan-kleshnin Keep in mind that the CSP policy only applies to content found after the meta tag is processed, so you should keep it towards the top of your document. I learned that the hard way. |
Sorry for commenting on a closed issue, but I (and a number of others) seem to be running into this issue with CSP errors using a nonce - it doesnt seem to work with inline styles among other things. @dbo is there a guide or example of implementing a SHA hash at all? I had a look at your PR but it didn't make much sense to me 🙁 |
Hello, I have the same problem - is there some docs around this topic ? |
I never got inline styles to work with my CSP, the case back then was emitting a hash for inline scripts ( |
Related #23993 |
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. |
Edit: This issue is very old and has now been replaced with #23993.
I don't see a way using next.js with a sensible CSP employed, foremost because it's eval'ing the component code (
unsafe-eval
is highly discouraged w.r.t. XSS). In addition, the injected scripts page component scripts should get a computed hash, and an SRI hash should be added for the CDN/next.js script.Excuse my ignorance about, but wouldn't it be better to use plain old script tag loading for the component module, props etc.?
The text was updated successfully, but these errors were encountered: