Question presented to candidate: "A security review flagged our Next.js app: no CSP, no HSTS, and it can be framed. Walk me through adding security headers, and a Content Security Policy strict enough that an injected script cannot run."
What a strong answer should cover:
- Static headers (HSTS,
X-Content-Type-Options,Referrer-Policy,Permissions-Policy, framing protection) belong inheaders()innext.config. - A strict CSP avoids
'unsafe-inline'by using a per-request nonce, generated inproxy.tsand sent on both the request (so Next.js can read it) and the response. - Next.js reads the nonce from the request's
Content-Security-Policyheader during rendering and adds it to its own scripts; your<Script>tags get it viaheaders().get("x-nonce"). - Nonces need dynamic rendering: a statically prerendered page has scripts without nonces, which the browser then blocks; this also rules out ISR, CDN caching of HTML and PPR shells.
- Alternatives and details: CSP without nonces in
next.config, experimental SRI (hashes),'strict-dynamic','unsafe-eval'only in development, and a matcher that skips static assets and prefetches.
Clarifying questions expected:
- "Must pages stay static or cacheable at the CDN?" β that decides between nonces and a weaker or hash-based policy.
- "Which third-party scripts must run?" β they need the nonce or an allowlisted origin.
Code / implementation expected: Yes β next.config headers plus a proxy.ts that sets a nonce-based CSP.