nonce本身不放行脚本,仅当服务端csp响应头、html标签nonce值、随机性三者严格对齐时才生效;否则报“refused to execute inline script”,常见原因包括响应头缺失、大小写/空格不匹配、meta设置无效、模板插值失败或js动态设置。

nonce 属性本身不放行任何脚本,它只是 CSP 的“匹配钥匙”——只有当服务端响应头、HTML 标签值、随机性三者严格对齐时,浏览器才允许对应 <script></script> 执行。
为什么加了 nonce 还报 “Refused to execute inline script”
这不是 HTML 写错了,而是 CSP 策略根本没生效或校验失败。真实原因通常有:
- 服务端压根没返回
Content-Security-Policy响应头(比如开发环境关了 CSP,或 CDN 缓存了旧响应) - 响应头写的是
script-src 'self' 'nonce-abc123',但 HTML 里是nonce="ABC123"(大小写不一致)或nonce="abc123 "(末尾空格) - 用
<meta http-equiv="Content-Security-Policy">设置策略——nonce在<meta>中完全无效,浏览器直接忽略 - 模板引擎插值失败,比如 Jinja2 漏了转义,导致生成的 HTML 中
nonce值为空或被截断
nonce 值必须由服务端生成,不能 JS 动态设置
浏览器在 HTML 解析阶段就完成校验,JS 执行时早已尘埃落定。以下写法毫无意义:
<script id="boot">
document.getElementById('boot').setAttribute('nonce','abc123');
</script>
正确做法只能是服务端渲染时注入:
<script nonce="<%= generateNonce() %>">
window.__CONFIG__ = { api: '/v1' };
</script>
generateNonce() 必须调用密码学安全随机函数,例如:
- Node.js:
crypto.randomBytes(16).toString('base64') - Python:
secrets.token_urlsafe(16) - PHP:
bin2hex(random_bytes(16))
值不能硬编码、不能复用、不能含空格/换行/中文/下划线等非法字符;每次 HTTP 响应都应生成新值。
哪些内联代码能用 nonce 放行,哪些不能
nonce 只对 <script></script> 标签内的脚本块或带 src 的外链脚本有效,对以下情况完全无效:
-
<button onclick="doIt()"></button>这类内联事件处理器——CSP 会直接拦截,报错明确写 “inline event handler” -
eval()、setTimeout("alert(1)")、Function("return 1")等动态代码执行 - 通过
innerHTML注入的脚本字符串(即使带nonce属性)
想让内联事件工作,只能重构为 addEventListener,或改用 script-src-elem 'unsafe-hashes' 配合哈希白名单(不推荐)。
真正难盯的从来不是怎么写 nonce,而是确保三件事是否始终对齐:服务端是否稳定下发 Content-Security-Policy 响应头、头里是否包含对应 'nonce-xxx'、每次生成的 nonce 值是否真正随机且编码合规——漏掉任一环,脚本就静默失效,连错误提示都不会有。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











