内联CSS的nonce必须配style-src而非script-src,且style标签的nonce属性须在HTML解析阶段就存在;服务端生成的nonce值需字符级完全一致地用于CSP头和style标签,并确保Goober等库执行前已定义window.__nonce__。

内联CSS的nonce必须配style-src,不是script-src
浏览器只认style-src 'nonce-xxx'这一条指令来放行带nonce属性的<style>标签。写成script-src 'nonce-xxx'完全无效,也不会报错——脚本照样被拦,样式照样被拦,静默失败。Goober、Emotion这类CSS-in-JS库注入的<style>元素,靠的就是这条规则。
style标签的nonce属性要手动写进HTML,不能靠JS补
和<script>一样,<style>标签的nonce属性必须在HTML解析阶段就存在。用document.querySelectorAll('style').forEach(s => s.nonce = nonce)是徒劳的:此时浏览器早已完成CSP校验,补上也没用。
- 服务端模板(如EJS、Nunjucks)中直接插值:
<style nonce="">body{color:red}</style> - SSR框架(如Next.js、Nuxt)需把nonce作为上下文变量传入,并确保生成的
<style>标签含该属性 - 若用Goober,它会自动读取
window.__nonce__并设到el.nonce,但前提是这个全局变量在Goober执行前已定义
服务端生成的nonce值必须同时用于CSP头和style标签
两个地方的值必须字符级完全一致:大小写、空格、Base64填充符(=)都不能差。常见翻车点:
- Node.js用
crypto.randomBytes(16).toString('base64')生成后,没过滤+、/、=——这些字符在HTTP头里可能被截断或转义 - 响应头写了
style-src 'nonce-abc123 '(末尾空格),而HTML里是nonce="abc123" - 用了
<meta http-equiv="Content-Security-Policy">——它不支持nonce,只响应头有效
Goober的window.__nonce__必须在加载前定义
Goober内部靠el.nonce = window.__nonce__自动挂载nonce,但它不检查window.__nonce__是否存在,也不做fallback。如果这个变量是异步加载或晚于Goober脚本定义,生成的<style>就会没nonce,CSP直接拦截。
立即学习“前端免费学习笔记(深入)”;
- 正确顺序:
<script>window.__nonce__ = 'xxx';</script>→<script src="goober.js"></script> - 不要用
defer或type="module"加载Goober,除非你确认window.__nonce__已在全局作用域可用 - 如果用打包工具(如Vite),注意HMR注入的runtime style标签是否也带nonce——Goober本身不处理这部分,得靠构建配置兜底
Content-Security-Policy字段,再核对<style>标签的nonce属性值,最后确认二者是否逐字匹配。


















