Content Security Policy (CSP) 是一种额外的安全层,用于检测和缓解特定类型的攻击,包括跨站脚本(XSS)和数据注入攻击。虽然 HTTPS 保证了数据传输的加密和完整性,但它无法防御网站本身存在的漏洞(如反射型 XSS 或 DOM XSS)。CSP 通过允许开发者定义可信资源来源的白名单,从而限制浏览器加载和执行的内容,显著增强站点的安全性。

1. CSP 的核心机制

CSP 通过 HTTP 响应头 `Content-Security-Policy` 或 HTML `<meta>` 标签来声明策略。浏览器根据策略规则限制以下行为:

- 脚本、样式、字体、图片、媒体等资源的加载来源;

- 是否允许执行内联脚本/样式(`unsafe-inline`);

- 是否允许使用 `eval()` 等动态执行代码(`unsafe-eval`);

- 表单提交目标;

- 框架嵌套(防止点击劫持);

- 以及报告违规行为等。

2. 为什么 HTTPS 需要 CSP 补充?

- HTTPS 的局限:HTTPS 仅加密传输层,防止中间人窃听或篡改,但无法阻止攻击者在用户浏览器中注入恶意脚本(例如通过评论框、搜索框等输入点)。

- CSP 的弥补:CSP 限制了浏览器只执行来自白名单的脚本,即使攻击者成功注入了恶意代码,如果该代码不在白名单内(如内联脚本或外部恶意域名),浏览器将拒绝执行并上报违规。

3. 常见 CSP 指令

指令   作用 

`default-src`   所有未单独指定资源的默认策略 

 `script-src`   控制 JavaScript 的来源 

`style-src`     控制 CSS 的来源 

 `img-src`    控制图片的来源 

 `connect-src`   限制通过 XHR、Fetch、WebSocket 等发起的连接 

`font-src`   控制字体文件的来源 

`object-src`     控制 `<object>`、`<embed>`、`<applet>` 等插件的来源 

 `media-src`    控制 `<audio>`、`<video>` 的来源 

`frame-src`    控制 `<iframe>` 的来源 

`report-uri` / `report-to`     指定浏览器上报违规行为的 URL 

 `upgrade-insecure-requests`   自动将页面中的 HTTP 请求升级为 HTTPS(防止混合内容) 

 `block-all-mixed-content`  (已废弃)阻止混合内容,现在被 `upgrade-insecure-requests` 替代 

4. 部署 CSP 的最佳实践

4.1 使用报告模式先行测试

在正式启用 CSP 前,先用 `Content-Security-Policy-Report-Only` 头收集违规报告,观察是否会影响现有功能。例如:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint

4.2 制定合理策略

- 从宽松开始,逐步收紧:初始阶段可以允许 `'self'` 和常用的 CDN 域名,并允许内联脚本/样式(但应尽量避免)。

- 尽量避免 `unsafe-inline` 和 `unsafe-eval`:这些会降低 CSP 的保护效果。如需内联脚本,可使用 nonce(随机数)或 hash方式。

- 使用 nonce 或 hash 替代内联:

  - nonce:为每个响应生成一个唯一的随机值,并在 CSP 中声明 `script-src 'nonce-abc123'`,同时给 `<script>` 标签添加相同的 `nonce="abc123"` 属性。

  - hash:计算内联脚本的哈希值(如 SHA-256),在 CSP 中声明 `script-src 'sha256-...'`。

- 升级混合内容:添加 `upgrade-insecure-requests` 指令,自动将页面中所有 HTTP 资源请求升级为 HTTPS,避免混合内容错误。

4.3 示例 CSP 头

http

Content-Security-Policy:

  default-src 'self';

  script-src 'self' https://trusted.cdn.com 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa';

  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;

  img-src 'self' data: https://images.example.com;

  font-src 'self' https://fonts.gstatic.com;

  connect-src 'self' https://api.example.com;

  frame-ancestors 'none';  # 防止点击劫持

  upgrade-insecure-requests;

  block-all-mixed-content; # 可选,upgrade-insecure-requests 已足够

  report-uri /csp-violation-endpoint;

4.4 监控与调整

- 搭建一个报告接收端点(如使用 [report-uri.io](https://report-uri.com/) 或自建服务),定期分析违规报告。

- 根据报告调整 CSP 策略,直到无意外违规后,再将 `Report-Only` 模式切换为强制模式。

5. 结合 HTTPS 的额外建议

- 确保所有资源均通过 HTTPS 加载:CSP 的 `upgrade-insecure-requests` 可以帮助自动转换,但最好从源头保证。

- HSTS(HTTP Strict Transport Security):同时启用 HSTS,强制浏览器始终通过 HTTPS 访问你的站点,并防止用户点击“继续访问”绕过证书警告。

- 证书强度:使用 2048 位及以上 RSA 或 ECDSA 证书,选择安全的 TLS 版本(TLS 1.2/1.3)。

6. 注意事项

- 兼容性:现代浏览器均支持 CSP Level 2/3,但部分老旧浏览器可能部分忽略。CSP 不会破坏老旧浏览器的基本功能,只是无法提供保护。

- 不要过度依赖 `unsafe-inline`:如果必须使用大量内联脚本,建议改用 nonce 方案。

- 动态生成内容:如果站点有用户生成内容(如评论区),需格外小心,确保 CSP 策略足够严格(例如不允许 `data:` 协议执行脚本)。

7. 总结

通过正确部署 CSP,即使攻击者成功在 HTTPS 站点上注入了恶意脚本,浏览器也会因为白名单限制而拒绝执行,从而有效抵御 XSS 等攻击。CSP 与 HTTPS 相辅相成,共同构建纵深防御体系。始终遵循“最小权限”原则,先测试后实施,并持续监控违规报告,就能在保障功能的同时最大化安全收益。