See how Stencil fits into the entire Ionic Ecosystem ->
Stencil is part of the Ionic Ecosystem ->

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.

In the world of Stencil applications, if your app leverages a restrictive CSP (i.e. anything other than 'unsafe-inline') and components without a Shadow DOM, you'll likely run into an error in the browser console stating the certain styles or scripts were not able to run because they violate the effective CSP.

To resolve this issue, we've implemented support for using CSP nonces in many of the Stencil output targets.

NOTE: CSPs and some CSP patterns are not supported by legacy browsers such as Internet Explorer. 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 Stencil. Instead, the server the application is hosted on will need to generate the nonce value for each page view, construct the CSP, and then correctly handle passing the generated nonce to Stencil 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 Stencil specifics, but we'll try to make those parts clear as we move on.

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 Stencil 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';
// We'll assume we have `autoDefineCustomElements` enabled
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, we cannot define/set the nonce 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, Stencil has fallback behavior for pulling the nonce off of the window object.

So, for SSR, your app can simply set the desired nonce value on window.nonce at bootstrap. Yes, this does involve some manual configuration for the code served by your server.

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

SSG

We cannot support CSP nonce with SSG. Because all of the code is generated during pre-rendering, we don'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.

BackNext
Contributors