CSP chống XSS bằng cách chỉ cho phép script từ nguồn tin cậy. Vì Next.js inline một số script (cho hydration), bạn cần nonce — một token ngẫu nhiên gắn vào thẻ <script> hợp lệ; trình duyệt chặn mọi script không có nonce đúng.
Tạo nonce trong middleware rồi truyền qua header để layout đọc lại:
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(request) {
const nonce = btoa(crypto.randomUUID())
const csp = `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'; object-src 'none';`
const headers = new Headers(request.headers)
headers.set('x-nonce', nonce)
const res = NextResponse.next({ request: { headers } })
res.headers.set('Content-Security-Policy', csp)
return res
}Trong Server Component: const nonce = (await headers()).get('x-nonce') rồi gán cho next/script.
Tại sao phải mới mỗi request: nonce hardcode/lặp lại thì kẻ tấn công đoán được và inject script kèm nonce đó → CSP vô tác dụng. Nonce dùng-một-lần buộc response phải động (không cache full-page tĩnh).
CSP prevents XSS by only allowing scripts from trusted sources. Since Next.js inlines some scripts (for hydration), you need a nonce — a random token attached to legitimate <script> tags; the browser blocks any script without the correct nonce.
Generate the nonce in middleware, then pass it via a header so the layout can read it back:
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(request) {
const nonce = btoa(crypto.randomUUID())
const csp = `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'; object-src 'none';`
const headers = new Headers(request.headers)
headers.set('x-nonce', nonce)
const res = NextResponse.next({ request: { headers } })
res.headers.set('Content-Security-Policy', csp)
return res
}In a Server Component: const nonce = (await headers()).get('x-nonce') then pass it to next/script.
Why fresh per request: a hardcoded/reused nonce can be guessed by an attacker who then injects a script with that nonce → CSP is useless. A one-time nonce forces the response to be dynamic (no fully-static full-page cache).