CodeWalk

CSP 中的 nonce 与 hash 严格模式脚本执行

作者:苦行僧 · 2026-05-30 12:55

请解释 CSP 中 nonce(随机数)和 hash(哈希)两种严格脚本执行策略的工作原理,以及如何在后端生成 nonce 并与前端模板配合。

回答

苦行僧

问题背景'unsafe-inline' 允许所有内联脚本执行,不安全。strict-dynamic 模式配合 nonce/hash 可实现精确控制。

Nonce(单次随机数)策略

# 响应头
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa';
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  console.log('这个脚本会执行');
</script>
<script>
  console.log('缺少 nonce,不会执行');
</script>

服务器端实现

// Express 示例
app.use((req, res, next) => {
  // 生成随机 nonce
  const nonce = crypto.randomBytes(16).toString('base64');
  res.locals.cspNonce = nonce;
  
  res.setHeader(
    'Content-Security-Policy',
    `default-src 'self'; script-src 'nonce-${nonce}' 'strict-dynamic'`
  );
  next();
});

// 模板中(EJS/Pug/React Helmet)
// <script nonce="<%= cspNonce %>">...</script>

Hash 策略

# 计算内联脚本的 SHA 哈希并添加到策略
Content-Security-Policy: script-src 'sha256-abc123...'
// 生成 hash
const crypto = require('crypto');
const script = 'console.log("fixed")';
const hash = 'sha256-' + crypto.createHash('sha256').update(script).digest('base64');
  • 适合不频繁变动的内联脚本
  • 脚本内容变化后需要更新 hash

strict-dynamic 机制

script-src 'nonce-abc123' 'strict-dynamic'
  • 允许 nonce 信任的脚本通过 document.createElement('script') 创建的新脚本执行
  • 无需为动态生成的脚本生成 nonce
  • strict-dynamic 会覆盖 'self''unsafe-inline'(在支持的浏览器中)

推荐实践:使用 nonce + strict-dynamic + fallback 白名单处理旧浏览器。