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 相辅相成,共同构建纵深防御体系。始终遵循“最小权限”原则,先测试后实施,并持续监控违规报告,就能在保障功能的同时最大化安全收益。