You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中如何全局配置带Nonce的Content Security Policy (CSP)

Next.js + 独立Express后端:Nonce方式实现CSP最佳实践

一、如何在_document中获取并传递Nonce?

_document.js作为Next.js服务端渲染的根文档组件,不支持getServerSideProps或getStaticProps,这是你之前尝试无效的核心原因。正确的实现路径如下:

  1. 在_document组件内生成唯一Nonce:
    用Node.js的crypto模块生成UUID并转成base64格式,确保每个请求的Nonce独一无二,避免复用带来的安全风险。
  2. 将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 07:58:24