CSP helps prevent cross-site scripting (XSS), clickjacking, and other injection attacks by restricting which sources can load content, scripts, styles, fonts, media, and more. It’s a critical layer of defense for modern web applications.
A nonce is a unique, random string generated per request. It allows specific inline scripts or styles to bypass strict CSP rules. Because the nonce changes with every request, attackers cannot predict or reuse it.
Use proxy.ts to generate a nonce and inject it into the CSP header:
export function proxy(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`.replace(/\s{2,}/g, ' ').trim()
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-nonce', nonce)
requestHeaders.set('Content-Security-Policy', cspHeader)
const response = NextResponse.next({ request: { headers: requestHeaders } })
response.headers.set('Content-Security-Policy', cspHeader)
return response
}Exclude static assets and prefetches from CSP enforcement:
export const config = {
matcher: [
{
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
missing: [
{ type: 'header', key: 'next-router-prefetch' },
{ type: 'header', key: 'purpose', value: 'prefetch' },
],
},
],
}x-nonce headers<Script> components using the nonce propTo support nonce injection, pages must be dynamically rendered. Use connection() to wait for a request:
import { connection } from 'next/server'
export default async function Page() {
await connection()
// Page content
}Use headers() to access the nonce:
import { headers } from 'next/headers'
import Script from 'next/script'
export default async function Page() {
const nonce = (await headers()).get('x-nonce')
return (
<Script
src="https://www.googletagmanager.com/gtag/js"
strategy="afterInteractive"
nonce={nonce}
/>
)
}Nonce-based CSP requires dynamic rendering. This disables:
'unsafe-inline'Setting a Content Security Policy with nonces in Next.js strengthens your app’s security posture. While it requires dynamic rendering and may impact performance, it’s essential for applications with strict security or compliance needs.