CSP内容安全策略:深度防御配置
CSP(Content Security Policy,内容安全策略)是浏览器层面的一道安全防线,用来限制页面能加载哪些资源、执行哪些脚本。如果说同源策略划定了"谁能访问我",那CSP就是"我能加载什么"。配置得当,它能有效缓解XSS、数据注入等攻击;配置失误,轻则策略失效,重则直接阻断正常功能。
一、CSP是什么,解决什么问题
CSP通过HTTP响应头Content-Security-Policy或HTML的<meta>标签声明,告诉浏览器:这个页面只允许从特定来源加载脚本、样式、图片、字体等资源,禁止内联脚本和eval等危险操作。
核心目标:
upgrade-insecure-requests自动升级HTTP请求report-uri或report-to收集策略违反日志二、CSP指令速查表
| 指令 | 作用 | 示例 |
|---|---|---|
| default-src | 默认资源策略,其他指令未设置时生效 | 'self' |
| script-src | JavaScript来源 | 'self' https://cdn.example.com |
| style-src | CSS来源 | 'self' 'unsafe-inline' |
| img-src | 图片来源 | 'self' data: https: |
| font-src | 字体来源 | 'self' https://fonts.gstatic.com |
| connect-src | XHR/WebSocket/Worker | 'self' |
| frame-src | iframe来源 | 'none' |
| media-src | 音视频来源 | 'self' |
| object-src | Flash/插件 | 'none' |
| base-uri | <base>标签允许的值 | 'self' |
| form-action | 表单提交目标 | 'self' |
| frame-ancestors | 谁可以嵌入本页(防点击劫持) | 'none' |
| upgrade-insecure-requests | HTTP自动升级HTTPS | 无值 |
| block-all-mixed-content | 阻止混合内容 | 无值 |
关键字
'none':完全禁止'self':同源(同协议+域名+端口)'unsafe-inline':允许内联脚本/样式(削弱安全性)'unsafe-eval':允许eval()和new Function()(削弱安全性)'strict-dynamic':允许由nonce/hash标记的脚本动态加载子脚本(推荐配合nonce使用)'nonce-<base64>':仅允许带有匹配nonce的内联脚本'sha256-<base64>':仅允许匹配哈希的内联脚本三、配置示例:从宽松到严格
1. 最基础的防护
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
2. 防御XSS的推荐配置
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-random123' 'strict-dynamic';
style-src 'self' 'nonce-random123';
img-src 'self' data: https:;
connect-src 'self';
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
script-src使用nonce + strict-dynamic,允许受信任脚本动态加载子脚本frame-ancestors 'none'3. 仅报告模式(Report-Only)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://report.example.com/csp;
4. 现代报告收集(Reporting API)
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Reporting-Endpoints: csp-endpoint="https://report.example.com/csp"
report-uri已废弃,新版浏览器使用report-to配合Reporting-Endpoints头。四、Nonce与Hash:内联脚本的出路
Nonce方式(推荐)
服务器生成随机nonce,每请求唯一:Content-Security-Policy: script-src 'nonce-abc123';
<script nonce="abc123">
console.log('这个脚本被允许执行');
</script>
Hash方式
计算内联脚本的SHA256哈希:Content-Security-Policy: script-src 'sha256-abc123...';
五、CSP的常见绕过与陷阱
1. unsafe-inline和unsafe-eval的滥用
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval';
unsafe-eval,但生产环境必须移除。2. 通配符和宽松域名
Content-Security-Policy: script-src *;
Content-Security-Policy: script-src https:;
Content-Security-Policy: script-src 'self' https://*.google.com;
*和https:允许任何来源的脚本,攻击者只需上传脚本到任意HTTPS站点即可绕过。*.google.com包含用户可上传内容的服务(如Google Sites、Firebase Hosting)。3. JSONP和Angular回调
如果策略允许https://api.example.com,而该域名提供JSONP端点:
<script src="https://api.example.com/data?callback=alert(1)"></script>
script-src的严格限制。4. data: URI的风险
Content-Security-Policy: script-src 'self' data:;
<script src="data:text/javascript,alert(1)"></script>
data:意味着任何人可以构造内联脚本。5. javascript:伪协议
<a href="javascript:alert(1)">click</a>
script-src很严格,javascript:伪协议在部分浏览器仍可能执行。需要配合default-src或明确禁止。六、实战:为现代Web应用配置CSP
React/Vue应用
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{nonce}' 'strict-dynamic';
style-src 'self' 'nonce-{nonce}' 'unsafe-inline';
img-src 'self' data: https: blob:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
unsafe-eval,生产环境必须去掉style-loader,需要unsafe-inline或改用MiniCssExtractPlugin使用Google Fonts
Content-Security-Policy:
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
使用Google Analytics / Tag Manager
Content-Security-Policy:
script-src 'self' https://www.google-analytics.com https://www.googletagmanager.com;
img-src 'self' https://www.google-analytics.com;
connect-src 'self' https://www.google-analytics.com;
七、CSP的局限与补充
CSP不是银弹:
innerHTML、DOM操作引入恶意内容,CSP无法阻止CSP应该作为纵深防御的一部分,配合输入过滤、输出编码、同源策略、WAF等共同使用。
八、检测与调试
浏览器DevTools
Chrome/Firefox的Network面板查看CSP头,Console面板查看违规报告:[Report Only] Refused to load the script 'https://evil.com/xss.js' because it violates the following Content Security Policy directive: "script-src 'self'".
在线验证工具
测试报告收集
// 监听securitypolicyviolation事件
document.addEventListener('securitypolicyviolation', (e) => {
console.log('CSP违规:', {
blockedURI: e.blockedURI,
violatedDirective: e.violatedDirective,
originalPolicy: e.originalPolicy
});
});
总结
CSP是浏览器送给Web开发者的安全礼物,但这份礼物需要正确拆开:
Report-Only开始,逐步收紧strict-dynamic,避免unsafe-inline配置得当的CSP,能让XSS攻击从"致命"降级为" nuisance"。