进入抖音 Web 的官网,打开 DevTools 可以看到 html 中的 link 和 script 标签中有很多 nonce 属性,没了解过的小伙伴可能会疑惑这个是干嘛用的?
先说结论:nonce 与浏览器的 CSP(Content Security Policy)策略有关,用于防止多种常见的网络攻击,例如 XSS(跨站脚本攻击)和数据注入攻击。
CSP 策略
核心内容
官网文档:developer.mozilla.org/en-US/docs/…
CSP 是通过 HTTP 响应头(通常是 Content-Security-Policy)或 <meta> 标签设置的。它提供了一系列指令,用于定义资源加载的安全策略。例如:
default-src: 设置默认的资源加载源。script-src: 限制 JavaScript 文件的加载源。style-src: 限制样式表(CSS)的加载源。img-src: 限制图像资源的加载源。font-src: 限制字体文件的加载源。connect-src: 限制 AJAX 请求和 WebSocket 连接的目标。frame-src: 限制<iframe>的嵌入内容源。
CSP 的影响
CSP 对以下方面有直接影响:
-
脚本执行:
- 阻止来自非信任源的脚本执行。
- 禁止内联 JavaScript 执行(除非使用
unsafe-inline,但这会降低安全性)。 - 防止动态创建的
<script>元素加载未经允许的内容。
-
资源加载:
- 限制外部资源(如图片、样式、字体等)的加载源。
- 阻止跨域资源的加载,除非被明确允许。
-
内联资源:
- 禁止内联 CSS 或内联 JavaScript,除非通过哈希值(
hash)或加密签名(nonce)明确允许。
- 禁止内联 CSS 或内联 JavaScript,除非通过哈希值(
-
Frame 嵌套:
- 防止未授权的嵌套内容,例如通过
frame-src限制恶意网站的 iframe 嵌套。
- 防止未授权的嵌套内容,例如通过
-
数据泄露防护:
- 防止未经允许的网络连接,从而减少敏感信息通过恶意请求泄露的风险。
配置示例
Content-Security-Policy:
default-src 'self';
script-src 'self' https://apis.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
解释:
- 仅允许同源加载默认资源。
- 仅允许加载来自
self和https://apis.example.com的脚本。 - 允许内联样式和同源样式表。
- 图像可以来自同源和
data:协议。
Nonce 的作用
在 CSP(Content Security Policy) 中,
nonce(number used once) 是一种用于验证内联脚本和样式安全性的随机值。这种机制允许内联资源被浏览器加载和执行,而不必通过放宽安全策略(例如使用unsafe-inline),从而在安全性与功能之间取得平衡。
nonce 的作用
当 CSP 策略中使用 nonce 时:
- 页面加载时,服务器会为每个请求动态生成一个唯一的、不可预测的随机字符串(即
nonce值)。 - 浏览器只会执行那些脚本或样式标签中包含匹配的
nonce属性的内容。 - 不包含匹配
nonce的资源将被阻止执行。
这种方法有效防止了攻击者通过 XSS(跨站脚本攻击)注入恶意脚本,因为攻击者无法预先知道随机生成的 nonce 值。
nonce 的工作机制
-
HTTP 响应头配置
nonceCSP 策略中使用nonce,如下所示:Content-Security-Policy: script-src 'self' 'nonce-abcdef123456'; style-src 'self' 'nonce-abcdef123456';在这段配置中,只有内联脚本和样式中包含
nonce="abcdef123456"的内容会被执行或应用。 -
HTML 中的内联资源加
nonce属性 在 HTML 文档中,内联脚本或样式需包含与 CSP 中指定的nonce值一致的属性:<script nonce="abcdef123456"> console.log('This script is allowed to execute.'); </script> <style nonce="abcdef123456"> body { background-color: lightblue; } </style> -
随机性和不可预测性 服务器应在每次请求时动态生成一个全新的
nonce,并且该值应该具有足够的随机性和长度,以防止被攻击者猜测。
使用 nonce 的优点
- 提升安全性 防止内联脚本和样式的注入攻击,即便攻击者试图在 HTML 中插入恶意脚本,也无法绕过
nonce验证。 - 兼容性 使用
nonce可以避免依赖unsafe-inline,从而符合更高的安全要求,同时保持一定的灵活性。 - 与动态生成的内容配合良好
nonce机制允许开发者在特定场景下安全地使用动态生成的内联脚本。
常见问题
-
如何生成
nonce? 通常由服务器端动态生成,可以使用随机字符串生成工具或函数,例如:// Node.js 例子 const crypto = require('crypto'); const nonce = crypto.randomBytes(16).toString('base64'); -
每次请求的
nonce必须不同 如果每次使用相同的nonce,会削弱安全性,攻击者可能复用已知的nonce值。 -
浏览器支持 现代浏览器均支持
nonce,但仍需确保您的 CSP 策略中不包含unsafe-inline,否则nonce无效。