Hash-based Strict Content Security Policy generator for Next.js to protect a single-page app (SPA) against XSS and CSP bypass.
Based on a study from Google:
- 95% of real-world CSP deployments are bypassed.
- 99.34% of hosts with CSP use policies that offer no benefit against XSS.
By using this package in your Next.js website you'll protect your single-page app (SPA) built with Next.js against XSS and CSP bypass.
With NPM:
npm install next-strict-csp
With YARN:
yarn add next-strict-csp
Integrate the CSP generator in your _document.tsx
this way:
_document.tsx
...
// Next.js libraries
import Document, { Html, Head, Main, NextScript } from 'next/document'
// Next Strict Content Security Policy
import { NextStrictCSP } from 'next-strict-csp'
...
// Enable Head Strict CSP in production mode only
const HeadCSP = process.env.NODE_ENV === 'production' ? NextStrictCSP : Head
...
// Document component
class MyDoc extends Document {
render() {
return (
<Html>
<HeadCSP>
{ process.env.NODE_ENV === 'production' &&
<meta httpEquiv="Content-Security-Policy" />
}
...
</HeadCSP>
<body>
...
<Main />
<NextScript />
...
</body>
</Html>
)
}
}
You can also integrate any additionnal inline scripts and they'll get hashed automatically. Here's an example to add Google Tag Manager and Cloudflare Analytics inline scripts:
_document.tsx
...
// Next.js libraries
import Document, { Html, Head, Main, NextScript } from 'next/document'
// Next Strict Content Security Policy
import { NextStrictCSP } from 'next-strict-csp'
...
// Cloudflare Insights Script (Optional)
const cloudflareJs = `var s = document.createElement('script')
s.src = 'https://static.cloudflareinsights.com/beacon.min.js'
s.setAttribute('data-cf-beacon', '{"token": "YOUR CLOUDFLARE WEB ANALYTICS TOKEN STRING"}')
document.body.appendChild(s)`
// Google Tag Manager Script (Optional)
const GTMJs = `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','YOUR GOOGLE TAG MANAGER ID STRING');`
// Next Strict CSP
// Inline scripts to hash (Optional)
NextStrictCSP.inlineJs = [
cloudflareJs,
GTMJs
]
...
// Enable Head Strict CSP in production mode only
const HeadCSP = process.env.NODE_ENV === 'production' ? NextStrictCSP : Head
...
// Document component
class MyDoc extends Document {
render() {
return (
<Html>
<HeadCSP>
{ process.env.NODE_ENV === 'production' &&
<meta httpEquiv="Content-Security-Policy" />
}
...
{/* Google Tag Manager */}
{ process.env.NODE_ENV === 'production' &&
<script
dangerouslySetInnerHTML={{
__html: GTMJs
}}
/>
}
{/* End Google Tag Manager */}
</HeadCSP>
<body>
{ process.env.NODE_ENV === 'production' &&
<noscript
dangerouslySetInnerHTML={{
__html: `<iframe src="https://www.googletagmanager.com/ns.html?id=YOUR GOOGLE TAG MANAGER ID STRING" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
}}
/>
}
...
<Main />
<NextScript />
{/* Cloudflare Web Analytics */}
{/*<script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon={`{"token": "YOUR CLOUDFLARE WEB ANALYTICS TOKEN STRING"}`}></script>*/}
{process.env.NODE_ENV === 'production' &&
<script dangerouslySetInnerHTML={{
__html: cloudflareJs
}} />
}
{/* End Cloudflare Web Analytics */}
...
</body>
</Html>
)
}
}
Live demo with Next.js Strict CSP for testing with website security scanner available here:
Guy Dumais
Learn more about website security and how to protect a Next.js website:
Website Security