CSP

CSP

这篇笔记还在编辑中,内容可能会继续补充、调整或重写。

CSP 的位置

Content Security Policy 通过 HTTP 响应头限制页面可以执行或加载的资源,是 XSS 的纵深防御。它不能替代按上下文编码、安全 DOM API、输入校验和依赖治理;错误策略也可能被页面中的脚本 gadget 绕过。

严格 CSP

只维护大量域名白名单的策略容易随着第三方服务膨胀,也可能信任托管用户内容的宽泛来源。现代严格 CSP 主要为允许执行的脚本分配每次响应唯一的 nonce,或为固定脚本声明 hash:

Content-Security-Policy:
  default-src 'self';
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  report-to csp-endpoint

nonce 必须由服务端为每个响应使用密码学安全随机数生成,并同时写入策略和允许的 <script>。不能使用固定 nonce、构建时常量或用户可控值。

从报告模式迁移

  1. 盘点内联脚本、动态脚本、Worker、连接和第三方资源。
  2. 先发送 Content-Security-Policy-Report-Only 收集违规。
  3. 对报告去重,并区分扩展、注入噪声和真实应用调用。
  4. 清理危险写法,加入 nonce/hash,再对小流量强制执行。
  5. 观察业务成功率和 CSP 违规,逐步扩大范围。

Report-Only 不提供阻止效果,不能长期被当作已经启用 CSP。

与其他策略组合

  • frame-ancestors 控制页面能否被嵌入,优先于旧式点击劫持头
  • object-src 'none'base-uri 'none' 收紧高风险能力
  • Trusted Types 限制字符串进入 DOM XSS Sink
  • SRI 可以验证跨源静态资源完整性,但要设计更新流程

样式、图片、字体和 API 的指令也应遵循最小权限,但不要为了消除报告就随意加入 *unsafe-inline 或宽泛域名。

实践验收

  • 策略通过 HTTP 响应头发送,而不只依赖 Meta 标签
  • nonce 每个响应唯一且不可预测
  • 应用不依赖 unsafe-eval 和无边界 unsafe-inline
  • Report-Only 报告经过归类,强制策略已在真实流量验证
  • CSP 违规能关联页面、版本和具体指令
  • 修改第三方脚本或框架配置后有回归检查

参考资料