- Next.js
- Security & Authentication Architecture
- Content Security Policy (CSP) & Nonces in Next.js
Content Security Policy (CSP) & Nonces in Next.js
Content Security Policy (CSP) prevents Cross-Site Scripting (XSS) and data injection attacks by restricting which scripts and resources can execute. In Next.js App Router, strict CSP is implemented using cryptographically random per-request nonces generated in Middleware/Proxy, passed via request headers, and applied to inline scripts and Next.js internal Flight hydration scripts.
Learning Objectives
Construct a strict Content Security Policy (CSP) header with script-src nonces.
Generate cryptographically secure nonces in Middleware and pass them via x-nonce headers.
Read nonces in root layout.tsx and attach them to <Script> and Next.js internal scripts.
Distinguish between build-time static routes and dynamic routes requiring per-request nonces.
Prerequisites & Background Knowledge
Why Interviewers Care
Advanced enterprise security requirement mandated in banking, healthcare, and enterprise SaaS applications.
The Challenge
How do you implement a strict Content Security Policy (CSP) with nonces in Next.js App Router? Demonstrate generating a nonce in Middleware and consuming it in the root layout.
Code Architecture & Implementation
1// middleware.ts2import { NextResponse } from 'next/server';3import type { NextRequest } from 'next/server';45export function middleware(request: NextRequest) {6 // 1. Generate a cryptographically random 16-byte base64 nonce7 const nonce = Buffer.from(crypto.randomUUID()).toString('base64');89 // 2. Build strict Content Security Policy10 const cspHeader = `11 default-src 'self';12 script-src 'self' 'nonce-${nonce}' 'strict-dynamic';13 style-src 'self' 'nonce-${nonce}';14 img-src 'self' blob: data: https:;15 font-src 'self';16 object-src 'none';17 base-uri 'self';18 form-action 'self';19 frame-ancestors 'none';20 upgrade-insecure-requests;21 `.replace(/\s{2,}/g, ' ').trim();2223 // 3. Set header on request so Server Components can read it24 const requestHeaders = new Headers(request.headers);25 requestHeaders.set('x-nonce', nonce);26 requestHeaders.set('Content-Security-Policy', cspHeader);2728 const response = NextResponse.next({29 request: {30 headers: requestHeaders,31 },32 });3334 // 4. Set CSP header on outgoing HTTP response35 response.headers.set('Content-Security-Policy', cspHeader);3637 return response;38}
Architectural Explanation
A strict CSP header instructs browsers to block any script not explicitly bearing an authorized cryptographic nonce attribute: <script nonce="...">. In Next.js, Middleware generates a unique base64 nonce using crypto.randomUUID() for every HTTP request. It sets this nonce in the Content-Security-Policy header and forwards it via x-nonce. The root layout reads the nonce via headers() and passes it to custom scripts, while Next.js automatically injects it into framework scripts.
Common Mistakes & Anti-Patterns
Using 'unsafe-inline' in script-src without nonces, nullifying XSS protection.
Reusing the same static nonce across multiple requests, allowing attackers to bypass CSP.
Forgetting that reading `headers()` in root layout makes all routes dynamic (unless using PPR or static CSP hashes).
Interview Follow-Up Traps
The interviewer asks: "Can you use nonces with completely static SSG pages?" No! A static page is generated once at build time; nonces must be unique per request. For static sites, hash-based CSP (`sha256-...`) is used instead.
Frequently Asked Questions
How do you test CSP without breaking production?
Use the `Content-Security-Policy-Report-Only` header to log violations to an endpoint before enforcing blocks.
Does Next.js support style nonces for CSS-in-JS?
Yes, passing the nonce to the root layout automatically secures Next.js inline style tags.
