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

2 comments

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

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

Leave a comment

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