如何配置 Content-Security-Policy 头部防止 XSS 攻击生效?

文章导读
配置 Content-Security-Policy (CSP) 头部是防止跨站脚本攻击 (XSS) 的有效手段,最推荐的做法是先在“报告模式”下运行收集策略,确认无误后再开启“强制模式”。
📋 目录
  1. A 命令速用版
  2. B 生产环境策略模板
  3. C Nonce 动态生成实现
  4. D 分步处理
  5. E 怎么验证是否生效
  6. F 常见坑
  7. G 参考来源
A A

配置 Content-Security-Policy (CSP) 头部是防止跨站脚本攻击 (XSS) 的有效手段,最推荐的做法是先在“报告模式”下运行收集策略,确认无误后再开启“强制模式”。

先说结论:直接开启强制策略容易导致网站功能异常,建议采用渐进式方案,先观察再拦截。

  • 先判断:梳理站内所有脚本来源,包括第三方 CDN 和内联脚本。
  • 优先做:配置 Content-Security-Policy-Report-Only 头进行灰度测试。
  • 再验证:通过浏览器控制台确认无报错后,切换为正式策略。

命令速用版

根据你的 Web 服务器类型,在响应头中添加 CSP 配置。以下是常见服务器的配置片段,初始阶段请使用 Report-Only 模式:

# Nginx 配置示例 (报告模式)
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline'; report-uri /csp-report; report-to \"csp-endpoint\"" always;
# Apache 配置示例 (报告模式)
Header set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline'; report-uri /csp-report; report-to \"csp-endpoint\""

注意:上述示例为了兼容性暂时保留了 'unsafe-inline',正式环境请替换为 nonce 或 hash。

生产环境策略模板

实际生产环境通常需要更细致的指令,以下是一个较为完整的策略模板,可根据实际情况裁剪:

default-src 'self';
script-src 'self' https://cdn.example.com 'nonce-{{random_nonce}}';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https://*.example.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
report-uri /csp-report;
report-to "csp-endpoint"

说明:script-src 中使用了 nonce 机制,style-src 暂时保留 unsafe-inline 以防样式错乱,建议后续逐步优化。

Nonce 动态生成实现

为了避免使用 unsafe-inline,建议为内联脚本生成随机 nonce。以下是一个 Node.js Express 中间件示例:

app.use((req, res, next) => {
  const nonce = Buffer.from(Math.random().toString(36)).toString('base64');
  res.locals.nonce = nonce;
  res.setHeader('Content-Security-Policy', `script-src 'self' 'nonce-${nonce}'`);
  next();
});

在 HTML 模板中引用:

<script nonce="<%= nonce %>">
  console.log('安全脚本执行');
</script>

分步处理

第一步:资产梳理

如何配置 Content-Security-Policy 头部防止 XSS 攻击生效?

检查页面引用的所有外部资源,包括 JavaScript、CSS、图片、字体以及 WebSocket 连接。特别注意第三方统计代码、广告联盟和 CDN 资源。

第二步:开启报告模式

在服务器配置中启用 Report-Only 模式。此模式下,浏览器会拦截违规资源并发送报告,但不会实际阻断页面展示,适合生产环境观察。注意同时配置 Report-To 头以支持新标准。

第三步:收集与分析报告

搭建接收报告的后端接口(如 /csp-report),或使用浏览器控制台手动查看违规记录。根据报告内容调整白名单,将必要的合法来源加入策略。

第四步:切换强制模式

当报告模式运行一段时间且无异常违规后,将 header 名改回 Content-Security-Policy,正式开启拦截。

怎么验证是否生效

打开浏览器开发者工具(通常按 F12),切换到“控制台”标签页。刷新页面后,如果 CSP 生效且存在违规资源,控制台会打印红色的 CSP 错误信息,例如" Refused to load the script... "。

在“网络”标签页中,被 CSP 拦截的请求状态通常显示为 (blocked:csp) 或类似标识。

如何配置 Content-Security-Policy 头部防止 XSS 攻击生效?

常见坑

1. 内联脚本被误杀

默认策略不允许<script>标签内直接写代码。如果需要保留,建议使用 nonce 或 hash 机制,而不是直接添加 unsafe-inline,后者会大幅降低安全性。

2. 第三方服务变更

引用的第三方 CDN 域名可能会变动,导致突然生效的 CSP 策略阻断业务。建议锁定具体子域名或定期复查。

3. 重定向丢失

部分服务器配置在发生 301/302 重定向时可能丢失自定义 header,需在配置中确保所有响应路径都携带 CSP 头。

4. report-to 兼容性

report-to 是较新的标准,旧版浏览器可能不支持。建议同时保留 report-uri 以确保报告能正常发送。

参考来源

  • MDN Web Docs: Content-Security-Policy - https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
  • OWASP: Content Security Policy Cheat Sheet - https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html