Generating a nonce for your application does not involve recompiling nginx anymore, thanks to dynamic modules!

Compile Dynamic Modules

  1. Get needed nginx modules

    Check the current version of nginx you’re using, then download the sources here: https://nginx.org/en/download.html

    Download the [Nginx Development Kit](https://github.com/simpl/ngx_devel_kit/releases) and the [set-misc-module](https://github.com/openresty/set-misc-nginx-module/releases).

    Extract the archives so that your folder structure looks like this:

    - nginx
      - nginx-1.17.10
      - ngx_devel_kit-0.3.1
      - set-misc-nginx-module-0.32
  2. Configure Arguments

    Grab the configure arguments of the nginx version currently installed on your server:

    nginx -V

    The output should look like this:

    nginx version: nginx/1.17.10 (Ubuntu)
    built with OpenSSL 1.1.1f  31 Mar 2020
    TLS SNI support enabled
    configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-Pmk9_C/nginx-1.17.10=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

    Save the arguments somewhere and add the references to ngx_devel_kit and set-misc-nginx-module to it:

    --add-dynamic-module=../ngx_devel_kit-0.3.1
    --add-dynamic-module=../set-misc-nginx-module-0.32

    Run ./configure with your arguments.

  3. Compile the modules

    It’s time to compile now!

    cd nginx-1.17.10
    make modules

    If compilation was successful, check the objs folder for these files:

    ngx_http_set_misc_module.so
    ndk_http_module.so
    

    bash

Load modules in Nginx

Upload the .so files to your server and put them in /usr/lib/nginx/modules.

Now edit your nginx.conf and load them before the http block:

load_module /usr/lib/nginx/modules/ndk_http_module.so;
load_module /usr/lib/nginx/modules/ngx_http_set_misc_module.so;

Generate and Replace Nonce

Open your virtual host file and put the following lines in the server block, replacing <NONCE_PLACEHOLDER> with a string of your choice:

> Use a unique value for <NONCE_PLACEHOLDER> and keep it safe!

# Generate and Replace NONCE
set_secure_random_alphanum $cspNonce 32;
sub_filter_once off;
sub_filter_types *;
sub_filter <NONCE_PLACEHOLDER> $cspNonce;

Update CSP Header

Update your CSP Header to include your nonce:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-$cspNonce'; object-src 'none'; style-src 'self' 'nonce-$cspNonce'; img-src 'self' data: blob:; media-src 'self'; frame-src 'none'; font-src 'self'; connect-src 'self'";

Add Nonce to your application

Add the following meta tag to the head of your html, replacing <NONCE_PLACEHOLDER> with your nonce-string:

<meta name="csp-nonce" content="<NONCE_PLACEHOLDER>" />

The nonce-string will be replaced by nginx with a unique nonce everytime the page is loaded.

Sources