2020-10-19 07:59:07
HTML5的nonce属性通过为内联脚本和样式提供一次性加密令牌,解决CSP中内联代码执行的安全问题,其核心作用是仅允许浏览器执行带有匹配nonce值的内联代码,从而防止恶意脚本注入。 以下是具体用法及增强CSP安全性的详细说明:
一、nonce属性的使用步骤服务器端生成唯一Nonce值
每次HTTP请求时,服务器需生成一个不可预测的随机字符串(如16字节Base64编码),确保每次请求的nonce值唯一。
示例代码:
Node.js:const crypto = require('crypto');const nonce = crypto.randomBytes(16).toString('base64');res.locals.cspNonce = nonce; // 传递给模板引擎
Python(Django/Flask):import secretsnonce = secrets.token_urlsafe(16) # 或 os.urandom(16).hex()
在CSP头部中包含Nonce
将生成的nonce值添加到HTTP响应头Content-Security-Policy中,指定允许执行内联代码的来源。
示例:Content-Security-Policy: script-src 'nonce-YOUR_GENERATED_NONCE' 'self'; style-src 'nonce-YOUR_GENERATED_NONCE' 'self';
'self'允许同源脚本和样式,nonce-YOUR_GENERATED_NONCE为当前请求的随机令牌。
在HTML标签中应用Nonce
所有需执行的内联<script>和<style>标签必须添加nonce属性,且值与CSP头部一致。
示例:<script nonce="<%= cspNonce %>"> console.log('合法脚本执行');</script><style nonce="<%= cspNonce %>"> body { background-color: lightblue; }</style>
模板引擎(如EJS)通过变量注入nonce值,确保与服务器端生成的值匹配。

unsafe-inline
全局放行所有内联代码,无论是否恶意,安全性极低,等同于“完全信任内联脚本”。
风险:攻击者注入恶意脚本时,CSP无法阻止,导致XSS攻击。
nonce
基于请求的一次性许可,仅允许匹配当前nonce值的内联代码执行。
优势:即使攻击者注入脚本,若无正确nonce值,浏览器会拒绝执行,有效防御XSS。
生成规范
加密安全随机数生成器:使用语言内置的CSPRNG(如Node.js的crypto.randomBytes、Python的secrets模块)。
避免弱随机源:禁用普通PRNG(如Math.random()),防止nonce被预测。
管理规范
每次请求生成新值:严禁复用nonce,否则攻击者可利用固定值绕过CSP。
存储在请求上下文:通过框架(如Express.js的res.locals)将nonce传递给模板,避免全局暴露。
模板引擎集成:确保模板能自动注入nonce到标签属性中。
常见误区
重用nonce值:导致防护失效,攻击者可利用固定值注入恶意脚本。
客户端暴露nonce:避免在全局JS变量中存储nonce,防止攻击者读取并伪造请求。
遗漏内联代码:确保所有合法内联脚本/样式均添加nonce,否则会被CSP阻止。
nonce不能替代其他CSP指令,需与以下策略结合形成多层次防护:
self与域名白名单
允许同源脚本及特定外部域名(如CDN):Content-Security-Policy: script-src 'nonce-YOUR_NONCE' 'self'
strict-dynamic指令
允许动态加载的脚本继承信任:Content-Security-Policy: script-src 'nonce-YOUR_NONCE' 'strict-dynamic' https:;
适用于通过document.createElement('script')动态加载的脚本,减少nonce管理复杂度。
资源类型限制
限制图片、字体、框架等资源的来源:Content-Security-Policy: img-src 'self'; font-src
违规报告
配置report-uri或report-to收集CSP违规事件,便于监控和调试:Content-Security-Policy: default-src 'self'; report-uri /csp-violation-report;
