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

Issue setting strict CSP in dev #11862

Closed
7 tasks done
justin-tay opened this issue Jan 31, 2023 · 7 comments · Fixed by #16052
Closed
7 tasks done

Issue setting strict CSP in dev #11862

justin-tay opened this issue Jan 31, 2023 · 7 comments · Fixed by #16052

Comments

@justin-tay
Copy link
Contributor

Describe the bug

I am trying to set a strict CSP in dev so that developers don't inadvertently introduce changes that will break the application in production where a strict CSP is applied.

In this case the CSP avoids setting unsafe-inline for style-src

Content-Security-Policy: style-src 'nonce-random' 'self' etc

When running in dev client.ts in Chrome the following errors are seen in console

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-random' 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-J+3YsBcGEYMOe4DwBHZqef/THcqobccvabWv1wEouI4='), or a nonce ('nonce-...') is required to enable inline execution.
updateStyle | @ | client.ts:377

I will try to submit a PR for this issue. Since unlike webpack there is no convention of where to take the nonce value from like in window.__webpack_nonce__ I will likely get it from a meta tag like marco-prontera/vite-plugin-css-injected-by-js#64

Reproduction

https://github.com/justin-tay/vite-csp-issue.git

Steps to reproduce

Configure vite.config.ts with a strict CSP that disallows unsafe inline for style-src

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    headers: {
      'Content-Security-Policy': `style-src 'nonce-random' 'self'`,
    },
  },
  plugins: [react()],
})

Run npm run dev

System Info

System:
    OS: Windows 10 10.0.22621
    CPU: (8) x64 Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
    Memory: 6.91 GB / 15.81 GB
  Binaries:
    Node: 18.13.0 - D:\dev\node\node.EXE
    Yarn: 1.22.19 - D:\dev\node\yarn.CMD
    npm: 8.19.3 - D:\dev\node\npm.CMD
  Browsers:
    Chrome: 109.0.5414.120
    Edge: Spartan (44.22621.1194.0), Chromium (109.0.1518.69)
    Internet Explorer: 11.0.22621.1

Used Package Manager

npm

Logs

No response

Validations

@J5Dev
Copy link

J5Dev commented Mar 18, 2023

I think this may be the exact issue I have been experiencing, as described/asked about over on the spatie/laravel-csp package discussion... spatie/laravel-csp#101

hopefully this will be merged in soon, as this holds us back from fully implementing a good content policy that we don't have to disable when developing locally :/

@GalacticHypernova
Copy link

GalacticHypernova commented May 31, 2023

Having the same issue here too.
I feel like changing vite's updateStyle internal behavior would entirely mitigate this conflict, as it can be changed to treat them as files, rather than stringifying them and defaulting to applying inline. It does not even respect styles that are already applied as files. However, if changing the internal process of applying styles on vite's part end isn't reasonable, it should at least treat and respect styles in files accordingly, in stead of breaking them. Nonces would only make it messier the more styles there are.

@Kagami
Copy link

Kagami commented Nov 20, 2023

Technically you can drop unsafe-inline for style-src in production but IMO it's very dangerous: some part of your code might depend on it and you will break production without noticing. Unless you have a solid QA team...

@gitRup-ca
Copy link

So it is still not fixed - a strict CSP using @Vite and Laravel? Has anyone done it? I can not find an answer/example anywhere. So I suggest do not waste your time (3 days now for me) apparently it is a very complex coding issue, and I mean that honestly. I love Laravel, Tailwind CSS, and OMG I love Spatie-CSP and would like to use Livewire. So this is what you do. Do NOT install Laravel JetStream it is too integrated with @Vite now. Create a new Laravel project. Install Fortify (brings in Sanctum as well). Install TailwindCSS. Then install Livewire which uses AlpineJS. Then use route level/group binding with multiple CSP headers as provided by Spatie. And after the guest has authenticated, give them the option to use Livewire reactivity which BREAKS a strict CSP. So a "MANAGER" has Livewire access but a visitor/guest does not. I am not waiting until a framework is built specifically for a strict CSP.

@schamberg97
Copy link

schamberg97 commented Jan 25, 2024

This is solvable through plugins, albeit it's frightening that Vite devs are unable to offer any solution to this question.

export default defineConfig(({ mode }) => {
  // something
  const viteClientRegex = /node_modules\/vite\/dist\/client\/client\.mjs$/gi;

    // regex'es to add CSP
  // TODO: make one normal regex to handle all three
  const regexScript = /<script(.*?)/gi;
  const replacementScript = `<script nonce="${nonce}"$1`;

  const regexStyle = /<style(.*?)/gi;
  const replacementStyle = `<style nonce="${nonce}"$1`;

  const regexLink = /<link(.*?)/gi;
  const replacementLink = `<link nonce="${nonce}"$1`;

  const nonce = mode === "development" ? "nonce" : "{SERVER-GENERATED-NONCE}";

  return {
    plugins: [
      {
        name: "transform-file",

        transform(src, id) {
          if (viteClientRegex.test(id)) {
            return {
              code: src.replace(
                "style.setAttribute('data-vite-dev-id', id);",
                `style.setAttribute('data-vite-dev-id', id); style.setAttribute('nonce', '${nonce.toString()}');`
              ),
            };
          }
        },
      },
      {
        name: "html-inject-nonce-into-script-tag",
        enforce: "post",
        transformIndexHtml(html) {
          return html
            .replace(regexScript, replacementScript)
            .replace(regexStyle, replacementStyle)
            .replace(regexLink, replacementLink);
        },
      },
    ],
  };
});

@gitRup-ca @justin-tay FYI. You should mostly be interested in the first plugin

If someone decides to make a plugin on NPM from this, I'd be grateful if you credit me (have no time ATM to package it all properly)

@tnabil
Copy link

tnabil commented Mar 14, 2024

@sapphi-red / @patak-dev - quick clarification on this: the mentioned issue solves this using a nonce, which is not suitable for generated / static applications. Are there any plans to implement support for these kinds of applications using hashes?

@sapphi-red
Copy link
Member

@tnabil We don't have any plans for that (at least for now). IMO that is easier to do it as a post-process because you'll need to obtain the hashes and set the header anyway. We might consider together with #2377.

@github-actions github-actions bot locked and limited conversation to collaborators Mar 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
8 participants