Christian
Christian

Reputation: 6440

How do I inject a CSP nonce into Angular's auto-generated script tags?

The Angular docs mention CSP, and Google's Security Engineers recommend against using whitelists. What I haven't figured out yet is how to inject a nonce into the script tag(s) that Angular injects into the index.html (to "bootstrap" itself). I suppose it has to do with Webpack, but the ng eject command has been removed from the cli a while ago, I believe, and I haven't been able to find a tutorial on this. Can anyone get me started with pointers, please?

The Webpack docs mention that a variable

__webpack_nonce__ = 'let-nonce-string-be-injected-by-server-here';

needs to be defied in the entry file (not the config - so an @angular-builders/custom-webpack npm module is probably not going to help?), but I'm not clear what Webpack's entry file is in the context of Angular...?

P.S.: Judging from this blog post, the polyfill file is one of the entry files - but it looks like it's not the first, so I doubt adding the variable there will work...?

Upvotes: 5

Views: 11947

Answers (1)

CSSBurner
CSSBurner

Reputation: 1991

If you are using Angular version less than 19, it will be ugly but it IS possible. Suppose you have a <meta> tag (within your document <head>) like this:

<head>
    ...
    <meta http-equiv="Content-Security-Policy" content="script-src 'strict-dynamic' 'nonce-rAnd0m' 'sha384-cw8QV0pYMDtz3Y6/mkyvB6TUzqZpq4rQD8j1sD/Y0wYSv7c10jG4qr8Y5F8vpuAb';">
    ...
</head>

You need to add a <script> tag IMMEDIATELY after <app-root>, which will inject a newly-generated (or server-generated) nonce using a regular expression replacement. Here is a script for injecting a 32-character nonce generated by the Crypto interface's method randomUUID() (link to MDN page):

<app-root></app-root>
<script nonce="rAnd0m">
    var random = (self.crypto.randomUUID() + self.crypto.randomUUID()).replace(/-/g, '').substr(0, 32); // or use server-generated random string
    var meta = document.querySelectorAll("meta[http-equiv]")[0];
    var csp = meta.getAttribute("content");
    meta.setAttribute("content", csp.replace(/\'nonce-/, "'nonce-" + random + "' 'nonce-"));
</script>

Upvotes: 0

Related Questions