A Content Security Policy(CSP) is a layer of security that can be added to websites via configuring a
Content-Security-Policy HTTP header. It helps to mitigate Cross Site Scripting (XSS).
Usually, CSPs are configured using an allowlist method, which can be bypassed in most configurations.
A strict CSP doesn’t suffer from these vulnerabilities, and is based on nonces (number used once) or hashes, which are generated on the server
and can’t be guessed by malicious users.
Implementing a strict CSP in NextJs SSR and App Router
For server-side rendered pages, creating a strict CSP with a nonce is very simple. We need to generate random nonce for every request,
and set it to the x-nonce header. We are using middlewares for this, as the nonce has to be unique for every request. Note, that for the script-src
directive, we also set the policy as strict-dynamic, this is essential for blocking scripts and styles that don’t have the nonce.
We can also access the nonce from a server component, by reading the headers:
Implementing a strict CSP in statically rendered pages (SSG)
There is a possibility that server-side rendering does not fulfill the performance requirements of the app, and we still need to set a
strict CSP. In this case, we need to create a unique hash of every inline script that is added to the app, and add it to the CSP. So, a malicious attacker
can’t inject new scripts, as their hash won’t match the hashes on the CSP.
This is extremely non-trivial, but thankfully, there is an npm package which comes to the rescue: @next-safe/middleware.
It will work out of the box for every strict CSP situation, be it SSR (which will add a nonce) or SSG (which will use hashes). Additionaly, it will also
work for pages that make use of ISR. It will also provide sensible defaults for CSP and other security headers.
This method will only work on apps using the Pages router, as with App Router it’s hard to
distinguish what’s SSG and what’s SSR.
Setting up
The example configuration below is adapted from the @next-safe/middleware documentation.
First,Install the package using NPM: npm i @next-safe/middleware.
Set up the custom middleware:
Configure pages/_document.tsx to use the custom components with CSP data:
Usage with GetServerSideProps
For every page that uses GetServerSideProps, we also need to use a custom function wrapper which will inject csp data:
Now your app will work automatically with both SSG and SSR and properly secure CSP headers.