nonce 是 CSP 中用于授权内联脚本和样式的随机一次性值,通过服务端每次请求生成唯一、不可预测的 Base64 随机字符串,并同步注入 HTTP 响应头 Content-Security-Policy 和 HTML 标签的 nonce 属性,使浏览器仅执行匹配的内联代码,从而防止 XSS。

什么是 nonce,它为什么能防 XSS
nonce 是 CSP(Content Security Policy)中用于白名单内联脚本和样式的随机一次性值。浏览器只执行或应用带有匹配 nonce 属性且该值出现在 HTTP 响应头 Content-Security-Policy 中的 <script> 或 <style> 标签。它不是靠“加密”起作用,而是靠“服务端生成 + 严格单次绑定 + 不可预测”来阻断攻击者注入恶意内联代码——因为攻击者无法提前知道这个每次请求都变的 nonce 值。
注意:nonce 只对内联内容有效(<script>alert(1)</script>、<style>body{color:red}</style>),对 src 或 href 外链资源无效;外链要用 sha256-xxx 或域名白名单。
怎么在 HTML 中正确写带 nonce 的 <script> 和 <style>
必须同时满足两个条件:HTTP 响应头含 nonce 值,HTML 标签带对应属性。缺一不可,顺序不重要,但值必须完全一致(包括大小写、空格)。
- 服务端需动态生成一个 Base64 编码的 16 字节以上随机字符串,例如
qBvK8xRzYmFtZmV0cG9sZQ==(别硬编码,每次请求都要新生成) - 响应头设置为:
Content-Security-Policy: script-src 'nonce-qBvK8xRzYmFtZmV0cG9sZQ=='(脚本)或style-src 'nonce-qBvK8xRzYmFtZmV0cG9sZQ=='(样式) - HTML 中写成:
<script nonce="qBvK8xRzYmFtZmV0cG9sZQ==">console.log('ok');</script> - 样式同理:
<style nonce="qBvK8xRzYmFtZmV0cG9sZQ==">body{margin:0}</style> - 如果同时用脚本和样式,且共用一个
nonce值,需在 CSP 头里合并声明:script-src 'nonce-xxx' style-src 'nonce-xxx'
nonce 常见失效原因和调试方法
页面报错 “Refused to execute inline script” 或 “Refused to apply inline style”,基本就是 nonce 没对上。常见坑点:
立即学习“前端免费学习笔记(深入)”;
- 服务端生成的
nonce值被缓存(比如模板引擎静态化、CDN 缓存了整个 HTML),导致多次请求用同一个值 ——nonce必须每请求一换 - CSP 响应头里的
nonce值多了一个空格或换行(比如拼接时用了\n),或用了 URL 编码但 HTML 标签里没解码 - HTML 标签里写了
nonce但响应头没配对应script-src或style-src指令(比如只写了default-src,它不继承nonce) - 用了
<script type="module">内联模块 —— 它不支持nonce,必须外链 - 浏览器开发者工具的 Network → Response Headers 里看不到 CSP 头?检查是否被中间件(如 Nginx、Express helmet)覆盖或删除了
Node.js / Python / PHP 中生成和注入 nonce 的关键点
不能手写固定值,也不能从 URL 或 cookie 读取——必须服务端真随机生成,并同步到响应头和模板变量中。
- Node.js(Express):
crypto.randomBytes(16).toString('base64'),然后用res.set('Content-Security-Policy', `script-src 'nonce-${nonce}'`),再把nonce传给模板(如 EJS:<script nonce="">) - Python(Flask):
secrets.token_urlsafe(16)或base64.b64encode(os.urandom(16)).decode(),用response.headers['Content-Security-Policy'] = f"script-src 'nonce-{nonce}'" - PHP:
base64_encode(random_bytes(16))(PHP 7+),确保 header() 在输出前调用,模板中直接 echo 变量 - 切记:不要在前端 JS 里尝试读取或构造
nonce,它必须由服务端独占控制;也不要把nonce放进日志或错误堆栈里,避免泄露
最易被忽略的是:同一页面多个内联 <script> 都得用同一个 nonce 值,但这个值不能复用到下一次请求——既要“单页一致”,又要“跨页唯一”。


















