nibtime / next-safe-middleware

Strict CSP (Content-Security-Policy) for Next.js hybrid apps https://web.dev/strict-csp/
https://next-safe-middleware.vercel.app
MIT License
78 stars 20 forks source link

Including hash values in directive breaks development #71

Open benhodgson87 opened 2 years ago

benhodgson87 commented 2 years ago

For our application we have a few HTML documents which are provided by an external API, which we then inject into a shadow dom to render to the user in a modal.

Because these documents contain some inline style blocks (primarily for formatting when the user downloads them directly from our API as a PDF) we're required to provide these to the CSP as hashes.

  csp({
    directives: {
      'style-src': [
        'self',
        'sha256-JThSIBBneZ9jfYuxRPMteq7vMYK+qmEWjgqofb4zbXw=',
        'sha256-cN1BZI26g9HtEaenSP0z9/KPaLYogAC2zI3QXkwzinM=',
        'sha256-v/lV8aPMxtV+yGN/Qn0NtrXNkB2LqRpllrxFoxqt7+k='
      ],
    },
    isDev: process.env.NODE_ENV === 'development'
  }),

In development, where isDev is set to true, this ultimately breaks all styles as the unsafe-inline value gets overridden by the hashes being present in the style directive.

Not sure of what the best fix for this would be, if there is one. As a workaround we've wrapped the hashes with a conditional to only spread them into the style directive if the environment isn't development, but this isn't ideal as it creates a difference between the CSP applied in dev vs. production.

Not sure if this is something that can be handled more correctly/elegantly in the library itself based on isDev, but I guess it too risks having unexpected side effects where manually provided hashes are required in the development environment.

nibtime commented 2 years ago

Hi @benhodgson87

you can resolve this, by adding arbitrary custom hashes with getCspInitialProps:

https://github.com/nibtime/next-safe-middleware/blob/c4075709fd8598ff3af27bafd25e0f298509dac5/apps/e2e/pages/_document.tsx#L39-L50

The concrete case why I added this was for dealing things like extractCritical of emotion to better support CSS-in-JS frameworks, but you can also pass your hashes as plain strings to hashRawCss. The hashes are only applied in production then, so it won't interfere with dev mode directive added by csp middleware. I could dcoument it here better: https://next-safe-middleware.vercel.app/guides/strict-csp-configuration#avoid-unsafe-inline-styles-css-in-js

I didn't expect your case in the csp middleware, therefore, but I could consider it, e.g by overiding hashes in dev mode when they are set n middleware

Edit: What I wrote above is wrong. You have to add the respective inline styles from your document as string to the array, they will be hashed then.