Skip to main content
Version: Next 🚧

Using Content Security Policy Nonces in Rindo

Content Security Policies (CSPs) can help protect an application from Cross-Site Scripting (XSS) attacks by adding a security layer to help prevent unauthorized code from running in the browser.

An application that is served with a CSP other than 'unsafe-inline' and contains web components without a Shadow DOM will likely run into errors on load. This is often first detected in the browser's console, which reports an error stating that certain styles or scripts violate the effective CSP.

To resolve this issue, Rindo supports using CSP nonces in many of the output targets.

caution

NOTE: CSPs and some CSP strategies are not supported by certain browsers. For a more detailed list, please see the CSP browser compatibility table.

How to Use a Nonce​

The actual generation of the nonce value and enforcement of the correct CSP are not the responsibility of Rindo. Instead, the server of the application will need to generate the nonce value for each page view, construct the CSP, and then correctly handle passing the generated nonce to Rindo based on which output target is being consumed.

There are many resources available that walk through setting up a CSP and using the nonce behavior. This article walks through the process using Nginx and Webpack. Obviously, these resources don't account for the Rindo specifics, but any specifics will be called out in this guide.

Per the MDN Guide on nonces, a nonce should be "a random base64-encoded string of at least 128 bits of data from a cryptographically secure random number generator".

Output Targets​

Using nonces may differ slightly between output targets, so please be sure to use the correct pattern based on the context in which your Rindo components are consumed.

Dist​

Consuming a nonce in the dist output target is easy using the provided setNonce helper function. This function is exported from the index file of the output target's designated output directory.

This function simply accepts the nonce string value that you want set for every style and script tag.

This is an example of consuming the dist output in an Angular app's entrypoint:

// main.ts

import { defineCustomElements, setNonce } from 'my-lib/loader';

// Will set the `nonce` attribute for all scripts/style tags
// i.e. will run styleTag.setAttribute('nonce', 'r4nd0m')
// Obviously, you should use the nonce generated by your server
setNonce('r4nd0m');

// Generic Angular bootstrapping
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.log(err));

defineCustomElements();

Custom Elements​

Consuming a nonce in the dist-custom-elements output target is easy using the provided setNonce helper function. This function is exported from the index file of the output target's designated output directory.

This function simply accepts the nonce string value that you want set for every style and script tag.

This is an example of consuming the dist-custom-elements output in an Angular app's entrypoint:

// main.ts

import { defineCustomElements, setNonce } from 'my-lib/dist/components';
// Assume `customElementsExportBehavior: 'auto-define-custom-elements'` is set
import 'my-lib/dist/components/my-component';

// Will set the `nonce` attribute for all scripts/style tags
// i.e. will run styleTag.setAttribute('nonce', 'r4nd0m')
// Obviously, you should use the nonce generated by your server
setNonce('r4nd0m');

// Generic Angular bootstrapping
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.log(err));

WWW​

Unfortunately, setting nonce attributes gets a bit trickier when it comes to SSR and SSG. As a nonce needs to be unique per page view, it cannot be defined/set at build time. So, this responsibility now falls on the hydrate app's execution of runtime code.

SSR

Since there is not an easy way (or any way) of exposing and executing helper functions to manipulate the outcome of the runtime code, Rindo has fallback behavior for pulling the nonce off of a meta tag in the DOM head.

So, for SSR, your app can simply inject a meta element into the header on each page request. Yes, this does involve some manual configuration for the code served by your server. To work correctly, the created tag must be generated as follows:

<meta name="csp-nonce" content="{ your nonce value here }" />

This isn't a security risk because, for an attacker to execute a script to pull the nonce from the meta tag, they would have needed to know the nonce ahead of the script's execution.

SSG

Rindo cannot support CSP nonces with SSG. Because all of the code is generated during pre-rendering, Rindo doesn't generate the style or script tags at runtime. If an application wants to leverage nonces in SSG, they can build a mechanism to scrape the pre-rendered code and apply the attribute server-side before it is served to the client.