bejamas / gatsby-plugin-csp

A Gatsby plugin which adds strict Content Security Policy to your project.
MIT License
38 stars 15 forks source link

Incorrect hashes being generated for styles and src? #18

Open bneigher opened 3 years ago

bneigher commented 3 years ago

Love this plugin, went from "what is CSP" to it's working in like 2 hours.

However I only got it working with the insecure directives:

directives: {
  'script-src': `'self' 'unsafe-inline' 'unsafe-eval' blob:`,
  'style-src': `'self' 'unsafe-inline',
  ...
}

I would like to get it working with the script and style hashes, but it seems that the generated hashes are not correct? When I have these options:

{
    resolve: `gatsby-plugin-csp`,
    options: {
        disableOnDev: false,
        reportOnly: false, // Changes header to Content-Security-Policy-Report-Only for csp testing purposes
        mergeScriptHashes: true, // you can disable scripts sha256 hashes
        mergeStyleHashes: true, // you can disable styles sha256 hashes
        mergeDefaultDirectives: false,
        directives: {
            'script-src': `'self' blob:`,
            'style-src': `'self' blob:`,
            'object-src': `'self' blob:`,
            'img-src': `'self' ...  blob:`,
            'connect-src': `'self' ... *.googleapis.com blob:`,
            'font-src': `'self' ... blob:`,
        },
    }
}

I see an error that implies incorrect hashing:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: 'sha256-VQmEp0Z3hhXpgyR8eLC7h/m/fuPoIu20hDeWkLfFJt8='". Either the 'unsafe-inline' keyword, a hash ('sha256-rstJb4fHq3envUwqc55dL7f2YwhXthb/y9glQxrlm+Y='), or a nonce ('nonce-...') is required to enable inline execution.

similar message for styles

Any ideas what I may be doing incorrect? Doesn't work in development nor production.

MHarmony commented 3 years ago

Same...

arielperez82 commented 3 years ago

Tracked it down to these two divs Gatsby wraps the body with: <div style="outline: none;" tabindex="-1" id="gatsby-focus-wrapper"> and <div id="gatsby-announcer" style="position: absolute; top: 0; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;" aria-live="assertive" aria-atomic="true"></div>

If you calculate the sha-256 for those two styles, you'll see they match the ones in the browser error i.e. xEAI9+h/o3bZk3pUT7XDH9K7x5IOvG0FbJpal6UC/m8= and g6+1wt4NLfWDgcHpASzi98yBTZMT5MvrI31KNOqoXC4=, respectively.

This plugin only calculates the sha-256 on <style> or <script> tags found in the head, pre-body, or post-body. It doesn't look for any in the body and also doesn't look for either inline style attributes or inline event handlers.

Most likely the same issue as #14 and #16

niklasnordlund commented 2 years ago

As a work around for the style attributes on gatsby-announcer and gatsby-focus-wrapper you can add a style-src config like this: 'style-src': "'self' 'unsafe-hashes' 'sha256-MtxTLcyxVEJFNLEIqbVTaqR4WWr0+lYSZ78AzGmNsuA=' 'sha256-o4LYhp5wtluJ8/NWUV2vi+r5AxmP8X2zEvYHCpji+kI='"

(unsafe-hashes option is required in some browsers to make it work for style attributes)

Note that if a future Gatsby update changes the style attribute on these divs these hashes would need to be updated again.

Also make sure you have mergeStyleHashes set to true for this to work.

Full example:

{
  resolve: 'gatsby-plugin-csp',
  options: {
    disableOnDev: true,
    mergeStyleHashes: true,
    mergeDefaultDirectives: true,
    directives: {
      'style-src':
        // hashes for #gatsby-focus-wrapper and #gatsby-announcer style attribute
        "'self' 'unsafe-hashes' 'sha256-MtxTLcyxVEJFNLEIqbVTaqR4WWr0+lYSZ78AzGmNsuA=' 'sha256-o4LYhp5wtluJ8/NWUV2vi+r5AxmP8X2zEvYHCpji+kI='",
    },
},
potatowave commented 2 years ago

As a work around for the style attributes on gatsby-announcer and gatsby-focus-wrapper you can add a style-src config like this: 'style-src': "'self' 'unsafe-hashes' 'sha256-MtxTLcyxVEJFNLEIqbVTaqR4WWr0+lYSZ78AzGmNsuA=' 'sha256-o4LYhp5wtluJ8/NWUV2vi+r5AxmP8X2zEvYHCpji+kI='"

(unsafe-hashes option is required in some browsers to make it work for style attributes)

Note that if a future Gatsby update changes the style attribute on these divs these hashes would need to be updated again.

Also make sure you have mergeStyleHashes set to true for this to work.

Full example:

{
  resolve: 'gatsby-plugin-csp',
  options: {
    disableOnDev: true,
    mergeStyleHashes: true,
    mergeDefaultDirectives: true,
    directives: {
      'style-src':
        // hashes for #gatsby-focus-wrapper and #gatsby-announcer style attribute
        "'self' 'unsafe-hashes' 'sha256-MtxTLcyxVEJFNLEIqbVTaqR4WWr0+lYSZ78AzGmNsuA=' 'sha256-o4LYhp5wtluJ8/NWUV2vi+r5AxmP8X2zEvYHCpji+kI='",
    },
},

I'm not clear on where this sha key should come from?

bneigher commented 2 years ago

@potatowave check the console CSP error/warning in the browser after a deployment and it will say hash was provided but was expected. Then just change it to <2>. That's how I did it.

In my case it looked like this: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: 'sha256-VQmEp0Z3hhXpgyR8eLC7h/m/fuPoIu20hDeWkLfFJt8='". Either the 'unsafe-inline' keyword, a hash ('sha256-rstJb4fHq3envUwqc55dL7f2YwhXthb/y9glQxrlm+Y='), or a nonce ('nonce-...') is required to enable inline execution.