Next.js中如何全局配置带Nonce的Content Security Policy (CSP)
Next.js + 独立Express后端:Nonce方式实现CSP最佳实践
一、如何在_document中获取并传递Nonce?
_document.js作为Next.js服务端渲染的根文档组件,不支持getServerSideProps或getStaticProps,这是你之前尝试无效的核心原因。正确的实现路径如下:
- 在
_document组件内生成唯一Nonce:
用Node.js的crypto模块生成UUID并转成base64格式,确保每个请求的Nonce独一无二,避免复用带来的安全风险。 - 将Nonce传递给关键组件:
- 给
<Head>组件添加nonce属性,让Next.js注入到头部的内联脚本/样式自动带上该Nonce - 给
<NextScript>组件传递nonce属性,确保Next.js核心脚本符合CSP规则
- 给
二、仅将Nonce添加到NextScript是否足够?
完全不够,你需要同步完成以下配置才能让CSP生效且不破坏页面功能:
- 给
<Head>组件配置Nonce:头部的内联样式、第三方脚本标签都需要Nonce授权 - 在CSP策略中明确包含Nonce:在
script-src、style-src等指令中加入'nonce-${nonce}',告知浏览器允许带有该Nonce的资源加载 - 配置第三方资源的允许规则:比如字体、API域名、图片来源等,需根据业务需求调整
代码示例
原无效代码(问题复现)
export default function Document() { // 尝试获取nonce的无效方式 return ( <Html> <Head> <link href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); } // 无效的getServerSideProps与getStaticProps
优化后的可行代码
import { Html, Head, Main, NextScript } from "next/document"; import crypto from "crypto"; export default function Document() { // 生成唯一Nonce,每个请求重新生成 const nonce = Buffer.from(crypto.randomUUID()).toString("base64"); // 配置CSP策略,按需替换业务域名 const cspHeader = ` default-src 'self' https://api.YOURDOMAIN.io; script-src 'self' 'nonce-${nonce}' https://api.YOURDOMAIN.io; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com; object-src 'none'; base-uri 'self'; form-action 'self'; block-all-mixed-content; upgrade-insecure-requests; `.replace(/\n/g, "").trim(); return ( <Html> <Head nonce={nonce}> {process.env.NODE_ENV === "production" && ( <meta httpEquiv="Content-Security-Policy" content={cspHeader} /> )} <link href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet" /> </Head> <body> <Main /> <NextScript nonce={nonce} /> </body> </Html> ); }
额外注意事项
- 若用Express后端统一设置CSP头,不要在
_document中重复配置,避免冲突;可通过middleware将Nonce注入到req对象,再在_document的getInitialProps方法中获取(Pages Router适用) - 开发环境可暂时关闭CSP,降低调试阻碍
'unsafe-inline'在style-src中是兼容部分CSS方案的临时配置,后续可尝试移除,改用Nonce授权内联样式
内容的提问来源于stack exchange,提问作者Oscar Ekstrand
相关产品推荐
相关产品推荐

