hectane logo

React Content Security Policy with nonce

How to add CSP nonce to React + Webpack app with Node and Nginx

React Content Security Policy with nonce

The main crux of the nonce is that: nonces must be regenerated for every page request and they must be unguessable.

The nonce attribute in the script lets you “whitelist” inline script and style elements, eliminating the need for the broader and less secure CSP unsafe-inline directive, thereby maintaining the fundamental CSP feature of prohibiting inline script and style elements in general.

Utilising the nonce attribute in script or style informs browsers that the inline content was deliberately included in the document by the server (nginx) rather than being injected by a potentially malicious third party.

The Content Security Policy article’s If you absolutely must use it section has a good example of how to use the nonce attribute in the script or style:

The react application is built using webpack, in the webpack config the NonceInjector Plugin is used to put a placeholder (_NONCE_) for the attribute nonce in script and style HTML tags.

<script
  defer="defer"
  src="/static/js/main.0405c3f1.js"
  nonce="_NONCE_"
></script>
<link href="/static/css/main.f855e6bc.css" rel="stylesheet" nonce="_NONCE_" />
Nonce Injector Webpack Plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");

class NonceInjector {
  constructor(NONCE_PLACEHOLDER) {
    this.NONCE_PLACEHOLDER = NONCE_PLACEHOLDER;
  }
  apply(compiler) {
    compiler.hooks.thisCompilation.tap("NonceInjector", (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).afterTemplateExecution.tapAsync(
        "NonceInjector",
        (compilation, callback) => {
          const { headTags } = compilation;
          headTags.forEach((tag) => {
            tag.attributes.nonce = this.NONCE_PLACEHOLDER;
          });
          callback(null, compilation);
        }
      );
    });
  }
}

module.exports = NonceInjector;

To verify the CSP nonce being changed in every request, need a server client setup and its done using docker

I have done 2 implementations here, one with Nodejs and another with Nginx

Express.js (Node server)

Express.js Node app serves the build app and replaces the nonce placeholder with the generated nonce on each request.

Github Code:  Expressjs Server Sample project

Node use Buffer and Crypto to generate the random nonce  in the server file

Nginx Server

Nginx serves the build react app and replaces the nonce placeholder with the generated nonce on each request. 

Github Code: Nginx Server Sample project

Nginx utilise the njs scripting to generate the random nonce string. Nginx Config file

Verify CSP Header

You can inspect each request and see the Content-Security-Policy added to the response headers with nonce

Here in the response each script and style tag will have the same nonce added to attributes.

Verify Nonce in script and style

If you already have a react - webpack app serving with either Node or Nginx you can utilise above NonceInjector Plugin and this setup to implement the CSP nonce.

Cheers  ✌️