Using a strong nonce based CSP with Angular

This article shows how to use a strong nonce based CSP with Angular for scripts and styles. When using a nonce, the overall security can be increased and it is harder to do XSS attacks or other type of attacks in the web UI. A separate solution is required for development and production deployments.

Code: https://github.com/damienbod/bff-aspnetcore-angular

When using Angular, the root of the UI usually starts from a HTML file. A meta tag with the CSP_NONCE placeholder was added as well as the ngCspNonce from Angular. The meta tag is used to add the nonce to the Angular provider or development npm packages. The ngCspNonce is used for Angular, although this does not work without adding the nonce to the Angular provider.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="CSP_NONCE" content="**PLACEHOLDER_NONCE_SERVER**" />
    <title>ui</title>
    <base href="/" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
  </head>
  <body>
    <app-root ngCspNonce="**PLACEHOLDER_NONCE_SERVER**"></app-root>
  </body>
</html>

The CSP_NONCE is added to the Angular providers. This is required, otherwise the nonce is not added to the Angular generated scripts. The nonce value is read from the meta tag header.

import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { ApplicationConfig, CSP_NONCE } from '@angular/core';
import { secureApiInterceptor } from './secure-api.interceptor';

import {
  provideRouter,
  withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { appRoutes } from './app.routes';

const nonce = (
  document.querySelector('meta[name="CSP_NONCE"]') as HTMLMetaElement
)?.content;

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
    provideHttpClient(withInterceptors([secureApiInterceptor])),
    {
      provide: CSP_NONCE,
      useValue: nonce,
    },
  ],
};

CSP in HTTP responses production

The UI now uses the nonce based CSP. The server can return all responses forcing this and increasing the security of the web application. It is important to use a nonce and not the self attribute as this overrides the nonce. You do not want to use self as this allows jsonp scripts. The unsafe-inline is used for backward compatibility. This is a good setup for production.

style-src 'unsafe-inline' 'nonce-your-random-nonce-string'; script-src 'unsafe-inline' 'nonce-your-random-nonce-string';

CSP style in development

Unfortunately, it is not possible to apply the style nonce in development due to the Angular setup. I used self in development for styles. This works, but has problems as you only discover style errors after a deployment, not during feature development. The later you discover errors, the more expensive it is to fix it.

Replace the values in the index.html

Now that the Angular application can use the nonce correctly, it needs to be updated with every page refresh or GET. The nonce is generated in the server part of the web application and is added to the index html file on each response. It is applied to all scripts and styles.

Links

https://nx.dev/getting-started/intro

https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

https://github.com/damienbod/bff-auth0-aspnetcore-angular

https://github.com/damienbod/bff-openiddict-aspnetcore-angular

https://github.com/damienbod/bff-azureadb2c-aspnetcore-angular

https://github.com/damienbod/bff-aspnetcore-vuejs

4 comments

  1. […] Using a strong nonce based CSP with Angular (Damien Bowden) […]

  2. […] Using a strong nonce based CSP with Angular – Damien Bowden […]

  3. enemypleasant3371948f0d's avatar
    enemypleasant3371948f0d · · Reply

    Using this example merged with an Angular 18 template, I’m running into problems with the CSP behaving differently in production and dev. Lazy loading components in routes for instance. “Refused to execute inline script because it violates the following Content Security Policy directive” errors block .svg .woff files unless specifically mentioned in Yarp Proxy config.

    So is using nonce really necessary? According to Mozilla.org: Note: Only use nonce for cases where you have no way around using unsafe inline script or style contents. If you don’t need nonce, don’t use it. If your script is static, you could also use a CSP hash instead.

    1. damienbod's avatar

      CSP nonce and CSP hash provide the same protection. The latest release of Angular seems to have a problem with nonces. I prefer nonces as I do not need to maintain and change hashes with every package update.

Leave a reply to The Morning Brew - Chris Alcock » The Morning Brew #3818 Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.