# Setting up Content Security Policy with JSS

Content Security Policy (CSP) is a way of whitelisting what resources the browser should allow to load (and reach out to). There are many excellent resources on CSP for more information. [This explanation](https://helmetjs.github.io/docs/csp/) is a good place to start.

In general, you should start with `Content-Security-Policy: default-src 'self';` and enable things as needed from there.

In the case of JSS, we need to set the `style-src` CSP directive. We don't want to just set it to `unsafe-inline` which will allow everything.

The solution is to include a _nonce_ (number used once):

[MDN/CSP/style-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src) notes the following:

> 'nonce-{base64-value}'
> A whitelist for specific inline scripts using a cryptographic nonce (number used once). **The server must generate a unique nonce value each time it transmits a policy. It is critical to provide an unguessable nonce, as bypassing a resource’s policy is otherwise trivial**. See [unsafe inline](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#Unsafe_inline_script) script for example.

Because the nonce must be generated to be unique and random for every request, this is not something that we can do at build time. Previously the docs suggested using the `__webpack_nonce__` variable with Webpack. However that is insecure because it never changes, so it could be trivially bypassed by an attacker, as noted in the Mozilla docs above.

To communicate the nonce value to JSS, we're going use some basic templating with an express server.

1.  In the server startup, we'll add middleware to generate the nonce.

    ```js
    // server.js
    import helmet from 'helmet'
    import uuidv4 from 'uuid/v4'
    import express from 'express'

    const app = express()

    app.use((req, res, next) => {
      // nonce should be base64 encoded
      res.locals.styleNonce = Buffer.from(uuidv4()).toString('base64')
      next()
    })

    app.use(
      helmet.contentSecurityPolicy({
        directives: {
          defaultSrc: ["'self'"],
          /* ... */
          styleSrc: ["'self'", (req, res) => `'nonce-${res.locals.styleNonce}'`]
        }
      })
    )
    ```

    (The above example uses [Helmet](https://helmetjs.github.io/) to set CSP directives).

    When loading the initial index page, the `Content-Security-Policy` header should now contain the nonce:

    ```
    default-src 'self'; style-src 'self' 'nonce-N2M0MDhkN2EtMmRkYi00MTExLWFhM2YtNDhkNTc4NGJhMjA3';
    ```

1.  Now we want to include this value in our page so that JSS can pick it up at runtime.

    You can use any templating engine, or if you have SSR, that should work too. For this example, we'll use the [Nunjucks](https://github.com/mozilla/nunjucks) template engine.

1.  First, create the template HTML file.

    ```html
    <head>
      <meta property="csp-nonce" content="{{ styleNonce }}" />
    </head>
    ...
    ```

1.  Now update the server to render the template with the `styleNonce` variable to be interpolated with the nonce generated from our middleware `res.locals.styleNonce`.

    ```js
    import express from 'express'

    const app = express()

    app.get('/', (req, res) => {
      res.render('index', {styleNonce: res.locals.styleNonce})
    })
    ```

    The tag must have `property="csp-nonce"` and have a `content` attribute with the string value to use as the nonce.

    Now JSS can apply the nonce to `<style />` elements: `<style nonce={nonce-value} />`

    At this point, the style blocks generated by JSS should render with the nonce value (`<style nonce />`) when you inspect the page.

    The browser might not show the nonce value inside the style tag when you inspect the page, but it's there regardless.

## Setting the nonce attribute in styling loaded by Webpack

You might still have some CSP violations if you use style/css/sass in addition to JSS. To fix this, set Webpack's `style-loader` to also set the nonce attribute to the placeholder template that we used above `{{ styleNonce }}`. This way, when the express server renders your HTML page as a template, it will fill in the proper nonce value.

```js
// webpack config
const config = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader',
            options: {attributes: {nonce: '{{ styleNonce }}'}}
          },
          'css-loader'
        ]
      },
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
            options: {attributes: {nonce: '{{ styleNonce }}'}}
          },
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  }
}
```

## Resources

- [MDN: Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [Helmet CSP configuration](https://helmetjs.github.io/docs/csp/)
- [Webpack nonce support PR](https://github.com/webpack/webpack/pull/3210)
- [JSS nonce support discussion](https://github.com/cssinjs/jss/issues/559)
