What’s a Nonce?
Tags: nonce, nginx, csp, angular
Published: 2023-10-25 21:50:36

---
title: What’s a Nonce?
published: true 
date: 2023-10-25 16:12:46 UTC
tags: nonce,nginx,csp,angular
canonical_url: https://blog.stackademic.com/whats-a-nonce-7508458bded9
---

![](https://cdn-images-1.medium.com/max/1024/0*ibvU-N6yux0jbODz)
_Photo by FLY:D on Unsplash_

What’s a _nonce_? It sounds like a creature in a Dr. Seuss book or maybe the lesser known de León brother. But in fact, it is one piece of an important security technique, and you should be aware of it. In this article, we will explore what a _nonce_ is and how it can be used to make an Angular application more secure.

### Content-Security-Policy (CSP)

To understand what a _nonce_ is, we first need to take a step back and talk about Content-Security-Policy or CSP. A CSP is one mechanism used to mitigate Cross-Site-Scripting (XSS) attacks which allow attackers to trick the browser into executing malicious content.

A CSP limits the _sources_ of content, so that the browser will only execute content from predefined sources or domains. To implement a CSP, the server adds a Content-Security-Policy response header that defines the acceptable sources. You can set values for default-src that apply to all content, or you can get more fine-grained and define sources for specific content. For example, script-src for scripts, style-src for styles, etc. It is common to set default-src ‘self’; which allows all content from the same domain as the site itself.

Setting a CSP also blocks all inline scripts and styles by default. Many applications, including Angular applications, need to execute inline scripts and styles to make the magic happen. Have you ever wondered how the encapsulated component styles actually work? Angular injects these at runtime and this functionality is blocked if you have a CSP.

The quick fix for this is to add the ‘unsafe-inline’ keyword like this:

```
script-src 'unsafe-inline'; style-src 'unsafe-inline';
```

This allows Angular to do what it needs to do. But of course, these settings are not limited to Angular scripts and styles _only_. These settings allow scripts and styles from _any_ source, effectively negating the CSP for scripts and styles. Enter the  **nonce**.

### The Nonce

_Nonce_ is a shortened form of “number used once”. It is a unique, ephemeral value that must be shared between the server and client. The server generates the value and applies it to the CSP like so (line breaks added for readability):

```
script-src 'nonce-0136435421e75d07b8128a50b805041d'; 
style-src 'nonce-0136435421e75d07b8128a50b805041d';
```

Then that _same_ nonce value must be applied to all inline scripts/styles. For example:

```
<script nonce="0136435421e75d07b8128a50b805041d">
// …
</script>
```

Now any inline script or style that has this nonce value can execute, without having to add ‘unsafe-inline’ to the CSP.

### How to Use a Nonce in Angular

If your Angular application has a CSP and you do not want to use ‘unsafe-inline’ (and you shouldn’t if you can help it), this is the _minimum_ policy you must have according to Angular (line breaks added for readability):

```
default-src 'self'; 
style-src 'self' 'nonce-randomNonceGoesHere'; 
script-src 'self' 'nonce-randomNonceGoesHere';
```

Since Angular 16, we can add a nonce value to the application element using the ngCspNonce attribute like so:

```
<app ngCspNonce="randomNonceGoesHere"></app>
```

You also have the option to provide the nonce using the CSP\_NONCE injection token, but this article will demonstrate the ngCspNonce attribute approach.

#### Adding the CSP and Nonce Locally

In the angular.json file, add this under architect.serve(line breaks added for readability):

```
"options": {
  "headers": {
    "Content-Security-Policy": "default-src 'self'; 
                                script-src 'self'; 
                                style-src 'self';"
  }
},
```

Run the project and you should see some ugly error messages like these:

![](https://cdn-images-1.medium.com/max/1024/1*Gyg1Ge_j2j4Okqyn3py_QA.png)
_Error message after applying a CSP_

Now add the ngCspNonce attribute to the app component:

```
<app ngCspNonce="randomNonceGoesHere"></app>
```

And change the previously added “Content-Security-Policy” in angular.json to this (line breaks added for readability):

```
"options": {
  "headers": {
    "Content-Security-Policy": "default-src 'self'; 
                                script-src 'self' 'nonce-randomNonceGoesHere';
                                style-src 'self' 'nonce-randomNonceGoesHere';"
  }
},
```

Stop and run the application again and see that the errors are gone because the _nonce_ (randomNonceGoesHere)on the scripts and styles match the _nonce_ on the CSP. It’s ok that we’re just using randomNonceGoesHere and not replacing it because the CSP we added in angular.json only applies when using ng serve. This is just for testing locally.

#### Adding the CSP and Nonce in Deployed Environments

Now we are fixed up locally, but how will this work in a deployed environment? For the deployed application, we will have to do some work on the server to add the CSP response header.

I am going to show an example using [Nginx](https://docs.nginx.com/nginx/admin-guide/web-server/). I will assume familiarity with Nginx. If you are not familiar with it, take a look at this [post](https://dev.to/seanbh/how-to-serve-an-angular-application-with-nginx-d9a) to see how to get an Angular application running locally with Nginx.

In a deployed environment, we need Nginx to substitute an acceptable nonce for randomNonceGoesHere, both in the CSP and in the index.html file where the app component lives. You’ll recall that this is where we added the ngCspNonce attribute.

I am going to show an example using the $request\_id that Nginx generates for each request. Nginx says the $request\_id is a “unique request identifier generated from 16 random bytes, in hexadecimal”. To my mind, this is an acceptable nonce value, but your security team should be consulted before implementing in Production to determine if you should _also_ make it cryptographically secure. But I want to keep this example simple, so I won’t here.

In the nginx.conf file, add these lines in the server block (which are documented with comments):

```
# add CSP, using nonce-$request_id ($request_id is unique request identifiery generated from 16 random bytes, in hexadecimal)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-$request_id'; style-src 'self' 'nonce-$request_id';";

# substitute as many values as are found (not just one)
sub_filter_once off;

# substitute randomNonceGoesHere in the index.html file (ngCspNonce="randomNonceGoesHere") with
# the $request_id so that it matches the nonce-$request_id in the CSP
sub_filter randomNonceGoesHere $request_id;
```

Now for each request, a Content-Security-Policy header will be added with a unique nonce value for scripts and styles, and the same nonce value will be passed to Angular via the ngCspNonce attribute, and all will be well!

### Content-Security-Policy-Report-Only

One last thing to mention is the Content-Security-Policy-Report-Only header. This is just like the Content-Security-Policy header, except that it only _reports_ failures rather than actually blocking execution.

So, if you have a lot of work to do before you can eliminate ‘unsafe-inline’, you can set up the Content-Security-Policy-Report-Only header to not allow ‘unsafe-inline’ and see what would break if you were to turn it on for real. This could be helpful if you want to eliminate ‘unsafe-inline’ but can’t do it in one fell swoop.

That’s it! I hope you found this useful.

### Bibliography

- [Angular — Security](https://angular.io/guide/security#content-security-policy)
- [unsafe-inline ⟶ CSP Guide (content-security-policy.com)](https://content-security-policy.com/unsafe-inline/)
- [Content Security Policy (CSP) — HTTP | MDN (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [nonce — HTML: HyperText Markup Language | MDN (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce)
- [Content-Security-Policy-Report-Only — HTTP | MDN (mozilla.org)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only)
- [http://nginx.org/en/docs/http/ngx\_http\_core\_module.html#var\_request\_id](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_id)
- [Module ngx\_http\_headers\_module (nginx.org)](http://nginx.org/en/docs/http/ngx_http_headers_module.html)
- [Module ngx\_http\_sub\_module (nginx.org)](http://nginx.org/en/docs/http/ngx_http_sub_module.html)

* * *