Next.js每次应用加载生成新nonce实现CSP strict-dynamic规则问题咨询
问题根因
- 你定义的
generatedNonce是next.config.js模块顶层的立即执行函数,Next.js加载配置文件时只会执行一次,仅在项目构建、开发服务启动时生成固定值,直到下次重启/重建才会更新,自然不会随每次页面请求刷新。 - next.config.js中的
headers配置项返回的是静态规则,构建阶段就会预生成,不支持每次请求动态计算值。
修复方案
要实现每次请求生成新nonce,需要用Next.js的动态请求处理能力,根据你使用的路由模式选择对应方案:
方案1:Pages Router 自定义_document实现
- 先清空next.config.js中CSP配置的nonce相关内容,移除
generatedNonce的顶层定义和publicRuntimeConfig中的对应配置。 - 新增/修改
pages/_document.js,示例代码如下:
import Document, { Html, Head, Main, NextScript } from 'next/document' import { v4 } from 'uuid' import crypto from 'crypto' import { createSecureHeaders } from "next-secure-headers"; class MyDocument extends Document { static async getInitialProps(ctx) { // 每次请求生成新nonce const hash = crypto.createHash('sha256'); hash.update(v4()); const generatedNonce = hash.digest('base64'); const initialProps = await Document.getInitialProps(ctx) // 动态设置CSP响应头 const cspHeaders = createSecureHeaders({ contentSecurityPolicy: { directives: { defaultSrc: ["'none'"], scriptSrc: [ ...(process.env.NODE_ENV === 'development' ? ["'unsafe-eval'"] : []), `'nonce-${generatedNonce}'`, "'strict-dynamic'", ], }, }, nosniff: "nosniff", referrerPolicy: "no-referrer", frameGuard: "sameorigin", }) cspHeaders.forEach(header => { ctx.res.setHeader(header.key, header.value) }) return { ...initialProps, generatedNonce } } render() { return ( <Html> <Head /> <body> <Main /> {/* 给Next内置脚本加上nonce */} <NextScript nonce={this.props.generatedNonce} /> </body> </Html> ) } } export default MyDocument
- 你自己添加的自定义script标签也要手动加上
nonce={this.props.generatedNonce}属性。
方案2:App Router Middleware实现
如果使用App Router,在项目根目录新增middleware.js,每次请求时生成nonce、设置响应头,同时将nonce通过请求头传递给页面组件使用,给所有script标签添加对应nonce属性即可。
内容的提问来源于stack exchange,提问作者v-i-s-h-n-u-ps
相关产品推荐
相关产品推荐

