Skip to content
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

2 cases where nonce isn't applied for Content-Security-Policy #21925

Closed
TheThirdRace opened this issue Feb 6, 2021 · 13 comments
Closed

2 cases where nonce isn't applied for Content-Security-Policy #21925

TheThirdRace opened this issue Feb 6, 2021 · 13 comments
Assignees
Labels
bug Issue was opened via the bug report template. please verify canary The issue should be verified against next@canary. It will be closed after 30 days of inactivity

Comments

@TheThirdRace
Copy link

TheThirdRace commented Feb 6, 2021

What version of Next.js are you using?

10.0.6

What version of Node.js are you using?

12.18.2

What browser are you using?

Chrome

What operating system are you using?

Windows 10 (latest)

How are you deploying your application?

Vercel

Describe the Bug

What's the bug?

When trying to use a Content-Security-Policy with style-src 'self' 'nonce-r@nd0m', there are 2 cases where the nonce is not applied.

Because of these, we're forced to relax the Content-Security-Policy to use inline-unsafe.

Case 1: fouc inline <style> tag

Not sure what fouc is (flash of unstyled content?), but those styles don't have the nonce:

<style data-next-hide-fouc="true">
    body {
        display: none
    }
</style>
<noscript data-next-hide-fouc="true">
    <style>
        body {
            display: block
        }
    </style>
</noscript>

Workaround

Because those styles are "fixed", it's possible to use the sha- tag to pass to the Content-Security-Policy and avoid using inline-unsafe.

This is far from ideal given any changes on NextJs side implies a change in the Content-Security-Policy. A permanent solution is needed.

Case 2: Next/Image inline style= prop

The use of styles= prop directly on the wrapper elements and the img element themselves is simply incompatible with the Content-Security-Policy.

I've been vocal lately about how much the inline styles are completely screwing us over for styling the Next/Image component. The Content-Security-Policy is is just another reason not to rely on inline styles.

The styling of Next/Image needs to be refactored, it's way too restrictive and problematic. See #18585, I made 3 comments there that explains pretty much all the current problems with styling, including the Content-Security-Policy.

Workaround

None whatsoever.

We're stuck using inline-unsafe in our Content-Security-Policy.

Expected Behavior

Case 1: fouc inline <style> tag

There are examples out there where you can simply pass the nonce to the <Head> component:

// _document.tsx
import Document, { DocumentContext, DocumentInitialProps, Head, Html, Main, NextScript } from 'next/document'
import { ReactElement } from 'react'
import { Favicon } from '../component/presentational/Favicon'
import { ResourceHint } from '../component/presentational/ResourceHint'

class MyDocument extends Document {
    static async getInitialProps(context: DocumentContext): Promise<DocumentInitialProps> {
        const initialProps = await Document.getInitialProps(context)
        return { ...initialProps }
    }

    render(): ReactElement {
        const nonce = '12345'
        return (
            <Html dir='ltr' lang='en'>
                <Head {...{ nonce }} />
                <body>
                    <Main />
                    <NextScript />
                </body>
            </Html>
        )
    }
}

export default MyDocument

I would expect the nonce to be applied to those 2 <style> tags like it is to all the other <style> tags from NextJs.

Case 2: Next/Image inline style= prop

No use of styles= prop directly on the wrapper elements and the img element themselves.

I don't see anything else that could solve the problem for both the Content-Security-Policy and the styling problems experienced by most developers.

This might require a refactor of how Next/Image actually works. Maybe have a component that only manage the nuts and bolts (lazy loading, placeholder, srcset, etc.), not the styling itself. Have another component take care of styling if need be, as long as it's not inline...

To Reproduce

Run a normal NextJs project.

In next.config.js:

module.exports = {
    async headers() {
        const contentSecurityPolicyHeader = {
                // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
                key: 'Content-Security-Policy',
                value: [
                    `base-uri;`,
                    `child-src;`,
                    `connect-src 'self';`,
                    `default-src;`,
                    `font-src;`,
                    `form-action;`,
                    `frame-ancestors 'self';`,
                    `frame-src 'self';`,
                    `img-src 'self' data:;`,
                    `manifest-src 'self';`,
                    `media-src 'self';`,
                    `object-src 'none';`,
                    `script-src 'self';`,
                    `style-src 'self' 'nonce-12345';`
                ].join(' ')
            },
        }

        return [
            {
                source: '/',
                headers: contentSecurityPolicyHeader
            },
            {
                source: '/:path*',
                headers: contentSecurityPolicyHeader
            }
        ]
    }
}

Add a Next/Image to your content:

import Image from 'next/image'

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
      />
      <p>Welcome to my homepage!</p>
    </>
  )
}

export default Home

Open the console in dev tools and refresh the page, you'll see the errors of styles being blocked


Edit: On 2021-10-22

I've read in another issue that the 2 <style> tags for "fouc" are only added in DEV. This means the CSP problem is not so bad given it doesn't happen in PROD.

As for the inline styles in next/image, I think they could be moved to styled Jsx method and work with the CSP. I haven't tried it myself because there was many other problems with using next/image. That's why I made my own implementation using Chakra-ui, which bypassed all the inline style problems. That's why I'm thinking it should be possible to move all inline-styles to styled-jsx as NextJs include it by default and it does the same as EmotionJs does for Chakra.

The one thing I haven't solved is to create a nonce in SSG. My current thinking is to use a Cloudflare Worker with the HTMLRewriter plugin to overwrite the nonce on the static file just before it's served to the browser. I'm 99% confident this would work.

This also begs the question if NextJs could do the same with its platform?

Technically, they already do fallback modes for pages and incremental rebuilds so they could probably use the same techniques to replace a nonce with a unique value on each load.

In any case, as long as next/image is still using inline styles, this ticket stays valid.

@TheThirdRace TheThirdRace added the bug Issue was opened via the bug report template. label Feb 6, 2021
@TheThirdRace
Copy link
Author

TheThirdRace commented Mar 13, 2021

Any word on this issue? It's been more than a month :(

I could understand not doing the Image part right away, but the nonce taken from the Head, which is already a feature of NextJs, should just be applied like NextJs does to all its other stuff (link, styles, etc). Those 2 style tags are the only thing NextJs doesn't cover...

@alex-r89
Copy link

I am also suffering from this issue, in fact the nonce doesn't seem to be working at all. However I believe you need to pass the nonce into your CSP header, for example:

script-src 'self' 'nonce-${nonce}';

I am unsure how you would generate the nonce in next.config.js and also pass it into _document.tsx. However a solution for generating it in the document can be can found here.

This apparently works, however I cant get it working. Refreshing the page multiple times will cause a Refused to execute inline script error. I am also finding errors with the nonce not applying to style-src when using styled components, but that in itself is a different issue.

So although your implementation may be wrong, I believe passing the nonce into the CSP header wont fix the issue.

@TheThirdRace
Copy link
Author

TheThirdRace commented Apr 29, 2021

@alex-r89
You are right, I did forget to include the nonce in the CSP header in my original post. I rectified it now, but it was only a copy/paste mistake for this post as I had it in my testing environment.

Although, it won't change anything. Even with the nonce it won't work because the 2 style tags aren't using it and the next/image component is using inline styles.

As for the link you posted, it's unfortunately only for SSR (server-side rendering). It won't work for SSG (static site generation).

Generating the nonce for SSG has been a real pain in the neck. I've posted in multiple issues, created one myself, visited the official discord, spent hours researching the problem and nobody at NextJs has ever even acknowledge the question. It's really frustrating because there's no workaround for this.

I can always use SHA hashes for the 2 problematic styles tags. I even rewrote the next/image component for myself to remove all the nonsense and inline styles. But I cannot get around the nonce generation issue in SSG... It's driving me crazy!

@alex-r89
Copy link

@TheThirdRace ah yes, that makes sense. Have you managed to fix the issue using a SHA then? I may need to give that a go.

Indeed, I am also now running into this issue and have noticed a number of people have spent a long time trying to get this working, to avail.

@TheThirdRace
Copy link
Author

@alex-r89 As mentioned, I did use the SHA for the 2 style tags that are missing the nonce and it works. I also rewrote next/image component to avoid using inline styles.

Even though I "fixed" those troubles, it doesn't matter in the end. I still can't generate a nonce in SSG (static site generation), which makes the whole exercise pointless...

@moigithub
Copy link

moigithub commented Jul 1, 2021

any news about this ?

i also noticed, using a custom headers in next.config with 'Content-Security-Policy'

module.exports = {
  async headers () {
    return [
      {
        source: '/',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: "default-src 'self'"
          }
        ]
      }
    ]
  }
}

the html output dont renders the nonce value from <Head nonce='123'>
it output <head nonce=""> and <script nonce=""> with blank/empty values
any other key works as expected

tested on
next v.10.2.3
next v.11.0.1

@TheThirdRace
Copy link
Author

@moigithub
Actually, it's normal to see <head nonce=""> and <script nonce=""> with empty values, Chrome is removing them so nobody can try to hack the nonce

But yeah, the 2 styles tags still don't have the nonce, which cause the CSP to block them if you're not using any hash for them. It's really annoying :(

@moigithub
Copy link

@moigithub
Actually, it's normal to see <head nonce=""> and <script nonce=""> with empty values, Chrome is removing them so nobody can try to hack the nonce

But yeah, the 2 styles tags still don't have the nonce, which cause the CSP to block them if you're not using any hash for them. It's really annoying :(

im viewing it on firefox, didnt check on chrome
WITHOUT the CSP header IT IS visible on firefox (not removed)
WITH the header its not present,
... so if it were the browser.. it should not be visible on any case

@TheThirdRace
Copy link
Author

@moigithub
Actually, it makes perfect sense that the browser doesn't remove it if the CSP is not present.

If you're using a CSP, it's 100% sure that a nonce on any HTML DOM element is related to it.

If you're NOT using a CSP, how the heck is the browser is supposed to know if that nonce you have on a div or a script isn't some attribute you set for something else?

Glad to know Firefox is also hiding the nonce.

@jankaifer jankaifer self-assigned this Dec 1, 2022
@jankaifer jankaifer added the please verify canary The issue should be verified against next@canary. It will be closed after 30 days of inactivity label Dec 1, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2022

Please verify that your issue can be recreated with next@canary.

Why was this issue marked with the please verify canary label?

We noticed the provided reproduction was using an older version of Next.js, instead of canary.

The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. You can think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running npm install next@canary and test it in your project, using your reproduction steps.

If the issue does not reproduce with the canary version, then it has already been fixed and this issue can be closed.

How can I quickly verify if my issue has been fixed in canary?

The safest way is to install next@canary in your project and test it, but you can also search through closed Next.js issues for duplicates or check the Next.js releases.

My issue has been open for a long time, why do I need to verify canary now?

Next.js does not backport bug fixes to older versions of Next.js. Instead, we are trying to introduce only a minimal amount of breaking changes between major releases.

What happens if I don't verify against the canary version of Next.js?

An issue with the please verify canary that receives no meaningful activity (e.g. new comments that acknowledge verification against canary) will be automatically closed and locked after 30 days.

If your issue has not been resolved in that time and it has been closed/locked, please open a new issue, with the required reproduction, using next@canary.

I did not open this issue, but it is relevant to me, what can I do to help?

Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the 👍 reaction on the topmost comment (please do not comment "I have the same issue" without repro steps). Then, we can sort issues by votes to prioritize.

I think my reproduction is good enough, why aren't you looking into it quicker?

We look into every Next.js issue and constantly monitor open issues for new comments.

However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.

Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.

Useful Resources

@TheThirdRace
Copy link
Author

Closing this issue:

  1. NextJS is not using the 2 style tags anymore; I think it's because of the new font loading mechanism
  2. There's no more wrappers with the new next/image component

While I'm not exactly sure the new next/image doesn't use inline styles, which is incompatible with the nonce, I don't care anymore... It's been 2 years already and I've long built my own implementation of next/image without any of the pain points of even the new implementation from NextJs 13. I'm done hoping for a fix...

@github-actions
Copy link
Contributor

github-actions bot commented Jan 1, 2023

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 1, 2023
@leerob
Copy link
Member

leerob commented Sep 1, 2023

Hey folks, wanted to swing back here with an update. After digging through many different issues and discussions, I've made a new page in the documentation (PR) specifically for Content Security Policy and nonces. This docs page:

  • Explains how to generate a nonce with Middleware
  • Shows how to consume the nonce in a route with headers()
  • Shows a complete CSP without needing to use any unsafe
  • Shows how to ignore the nonce Middleware from running on prefetches / static assets

Further, we've patched some bugs and made improvements to nonce handling in Next.js that will be available in the latest canary version (for those of you time traveling from the future, upgrade to Next.js 13.5). We also updated the with-strict-csp example in the examples/ folder, which is backlinked from the new documentation page.

Really hope this helps out, thank you all 🙏 I'll be closing this discussion out. To continue the discussion, please go here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. please verify canary The issue should be verified against next@canary. It will be closed after 30 days of inactivity
Projects
None yet
Development

No branches or pull requests

5 participants