Nonce与CSP的script-src白名单可共存,采用“或”逻辑匹配:'self'放行外部脚本,'nonce-xxx'放行对应内联脚本,二者缺一不可;strict-dynamic需置于nonce之后才生效。

script nonce 和 CSP 的 script-src 白名单怎么共存
nonce 不是用来替代白名单的,而是和白名单并列使用的补充机制。CSP 的 script-src 指令支持多个来源同时存在,比如 'self'、'nonce-abc123'、https://cdn.example.com 可以一起写,浏览器会“或”逻辑匹配——只要满足其中任一条件,脚本就可执行。
常见错误是以为加了 nonce 就能删掉 'self',结果导致外部 JS(如 CDN 上的 React、Lodash)加载失败。反过来,只留 'self' 却不配 nonce,内联脚本照样被拦。
-
Content-Security-Policy: script-src 'self' 'nonce-27f434278e6b79578d5c9f0a321c4567' https://cdn.example.com是合法且推荐的写法 - 外部脚本(
<script src="https://cdn.example.com/app.js"></script>)靠https://cdn.example.com匹配,不依赖 nonce - 内联脚本(
<script nonce="27f434278e6b79578d5c9f0a321c4567">init();</script>)靠 nonce 匹配,不依赖域名 - 如果用了
strict-dynamic,必须把'nonce-xxx'放在它前面,否则浏览器忽略strict-dynamic
为什么 script 标签写了 nonce 还被 Refused to execute inline script
根本不是标签写错了,而是两端值没对齐。浏览器校验 nonce 是逐字节比对,差一个空格、大小写、换行符都会失败。
典型现象:控制台报 Refused to execute inline script because it violates the following Content Security Policy directive,但你明明写了 <script nonce="abc123"></script>。
立即学习“前端免费学习笔记(深入)”;
- 响应头漏了
script-src 'nonce-abc123',或写成script-src 'nonce-ABC123'(大小写敏感) - 模板渲染时插值出错,比如 Jinja2 中
{{ nonce|safe }}实际输出了abc123\n,导致 HTML 变成nonce="abc123\n" - 用了全角等号或引号:
nonce="abc123"或nonce="abc123"(中文双引号) - Webpack/Vite 注入的 runtime 脚本(如 HMR、chunk 加载逻辑)没带 nonce,它们也是内联脚本,同样被拦
React/Vue 里怎么安全传 nonce 到动态生成的 script 标签
不能靠前端拼接,也不能从 URL 或 localStorage 读取——nonce 必须由服务端每次请求生成,并同步注入到 HTML 和响应头。
SSR 场景下,框架 hydration 会复用服务端 DOM,但若客户端 JS 动态创建 <script>,它不会自动继承 nonce。所以关键不是“怎么加属性”,而是“谁来决定该加什么值”。
- Next.js 推荐用
next-csp,它在服务端生成randomBytes(16),通过 Context 透传给组件,再用useNonce()拿到值绑定到标签 - Vue SSR 需在服务端上下文(如
context.nonce)里存好值,模板中直接写<script :nonce="nonce"> - 纯静态 HTML + Express?把 nonce 存进
res.locals.nonce,EJS 模板里用<script nonce=""> - 注意:Vite 默认不支持运行时 nonce 注入,得用
vite-plugin-csp或手动在index.html模板里预留占位符
Webpack 的 __webpack_nonce__ 为什么设了还是无效
设 window.__webpack_nonce__ = 'abc123' 只是第一步,Webpack 还要确认两件事:是否启用了 nonce 支持、是否把该值真正写进了生成的 <script> 标签里。
默认情况下,Webpack 打包产物里的 runtime 脚本(如 <script>__webpack_require__(...)</script>)是内联的,但它不会自动读取 __webpack_nonce__ 并写进标签属性——除非你显式配置。
- Webpack 5+ 需开启
output.trustedTypes或使用HtmlWebpackPlugin的meta选项注入 nonce 属性 - 更可靠的做法:在 HTML 模板中手动生成
<script nonce="abc123">...</script>,然后让 Webpack 把 runtime 代码塞进这个已有 nonce 的标签里 - Vite 用户别指望
define注入 nonce 字符串——那会变成构建时硬编码,失去“每次请求唯一”语义 - 最终检查点:打开 DevTools → Elements → 找到 Webpack 注入的
<script>标签,确认它确实有nonce="..."属性,且值和服务端响应头一致



















