答案
Content Security Policy(CSP,内容安全策略)是一种强大的安全机制,用于防止 XSS 攻击、数据注入攻击和其他类型的代码注入攻击。CSP 通过限制浏览器可以加载和执行的资源来源,有效地减少了攻击面。
CSP 的核心概念
定义: CSP 是一个 HTTP 响应头,它告诉浏览器哪些资源(如脚本、样式、图片、字体等)可以从哪些来源加载。通过定义白名单,CSP 可以防止恶意脚本的执行。
基本语法:
shellContent-Security-Policy: <policy-directive>; <policy-directive>; ...
CSP 的主要指令
1. default-src
设置所有资源类型的默认策略。如果没有为特定资源类型设置策略,则使用 default-src 的值。
shellContent-Security-Policy: default-src 'self';
2. script-src
控制 JavaScript 脚本的来源。
shellContent-Security-Policy: script-src 'self' https://trusted.cdn.com;
3. style-src
控制 CSS 样式表的来源。
shellContent-Security-Policy: style-src 'self' 'unsafe-inline';
4. img-src
控制图片的来源。
shellContent-Security-Policy: img-src 'self' data: https:;
5. connect-src
控制 XMLHttpRequest、WebSocket、EventSource 等连接的来源。
shellContent-Security-Policy: connect-src 'self' https://api.example.com;
6. font-src
控制字体的来源。
shellContent-Security-Policy: font-src 'self' https://fonts.gstatic.com;
7. object-src
控制 <object>、<embed>、<applet> 等元素的来源。
shellContent-Security-Policy: object-src 'none';
8. media-src
控制 <audio>、<video> 等媒体元素的来源。
shellContent-Security-Policy: media-src 'self' https://media.example.com;
9. frame-src
控制 <frame>、<iframe> 等框架元素的来源。
shellContent-Security-Policy: frame-src 'self' https://trusted-iframe.com;
10. base-uri
限制 <base> 元素可以使用的 URL。
shellContent-Security-Policy: base-uri 'self';
11. form-action
限制表单可以提交的目标 URL。
shellContent-Security-Policy: form-action 'self';
12. frame-ancestors
限制哪些页面可以将当前页面嵌入到 <frame> 或 <iframe> 中。
shellContent-Security-Policy: frame-ancestors 'none';
CSP 的源值
1. 'self'
只允许从同源加载资源。
shellContent-Security-Policy: default-src 'self';
2. 'none'
不允许从任何来源加载资源。
shellContent-Security-Policy: object-src 'none';
3. 'unsafe-inline'
允许内联脚本和样式(不推荐使用)。
shellContent-Security-Policy: script-src 'self' 'unsafe-inline';
4. 'unsafe-eval'
允许使用 eval() 和类似的函数(不推荐使用)。
shellContent-Security-Policy: script-src 'self' 'unsafe-eval';
5. 'strict-dynamic'
允许由可信脚本加载的脚本执行。
shellContent-Security-Policy: script-src 'self' 'strict-dynamic';
6. 'report-sample'
在违规报告中包含样本代码。
shellContent-Security-Policy: script-src 'self' 'report-sample';
7. 具体域名
允许从特定域名加载资源。
shellContent-Security-Policy: script-src 'self' https://cdn.example.com;
8. 通配符
允许从任何子域名加载资源。
shellContent-Security-Policy: script-src 'self' https://*.example.com;
9. 协议限定
允许从特定协议加载资源。
shellContent-Security-Policy: img-src https:;
CSP 如何防止 XSS 攻击
1. 阻止内联脚本执行
不安全的页面:
html<script> alert('XSS'); </script>
使用 CSP 防护:
shellContent-Security-Policy: script-src 'self';
结果: 内联脚本将被阻止执行。
2. 阻止 eval 执行
不安全的代码:
javascripteval('alert("XSS")');
使用 CSP 防护:
shellContent-Security-Policy: script-src 'self';
结果: eval() 调用将被阻止。
3. 限制外部脚本来源
不安全的页面:
html<script src="https://malicious.com/script.js"></script>
使用 CSP 防护:
shellContent-Security-Policy: script-src 'self' https://trusted.cdn.com;
结果: 来自恶意域名的脚本将被阻止加载。
4. 阻止动态脚本注入
不安全的代码:
javascriptconst script = document.createElement('script'); script.src = 'https://malicious.com/script.js'; document.body.appendChild(script);
使用 CSP 防护:
shellContent-Security-Policy: script-src 'self';
结果: 动态注入的脚本将被阻止加载。
CSP 的实施方式
1. 通过 HTTP 响应头
Node.js Express 示例:
javascriptapp.use((req, res, next) => { res.setHeader( 'Content-Security-Policy', "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" ); next(); });
Nginx 配置示例:
nginxadd_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;";
Apache 配置示例:
apacheHeader always set Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:"
2. 通过 HTML meta 标签
html<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">
注意: meta 标签方式不如 HTTP 响应头安全,因为某些攻击可能绕过 meta 标签。
CSP 报告模式
在实施 CSP 之前,可以使用报告模式(Report-Only)来测试策略,而不会阻止任何资源加载。
shellContent-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report
报告端点示例:
javascriptapp.post('/csp-report', (req, res) => { console.log('CSP Violation:', req.body); res.status(204).end(); });
CSP 违规报告
当 CSP 策略被违反时,浏览器会发送违规报告到指定的端点。
报告格式示例:
json{ "csp-report": { "document-uri": "http://example.com/page.html", "referrer": "http://example.com/", "violated-directive": "script-src", "effective-directive": "script-src", "original-policy": "default-src 'self'; script-src 'self'", "disposition": "report", "blocked-uri": "https://malicious.com/script.js", "line-number": 10, "column-number": 5, "source-file": "http://example.com/page.html", "status-code": 200, "script-sample": "" } }
CSP 最佳实践
1. 从严格策略开始
shellContent-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; base-uri 'self'; form-action 'self';
2. 逐步放宽策略
根据实际需求逐步添加允许的来源。
shellContent-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
3. 避免使用 'unsafe-inline' 和 'unsafe-eval'
不推荐:
shellContent-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval';
推荐:
shellContent-Security-Policy: script-src 'self' 'nonce-abc123';
4. 使用 nonce 或 hash
Nonce 示例:
html<script nonce="abc123"> // 这个脚本将被允许执行 </script>
shellContent-Security-Policy: script-src 'self' 'nonce-abc123';
Hash 示例:
html<script> alert('Hello'); </script>
shellContent-Security-Policy: script-src 'self' 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=';
5. 使用 report-uri 监控违规
shellContent-Security-Policy: default-src 'self'; script-src 'self'; report-uri /csp-report
6. 定期审查和更新策略
定期检查 CSP 违规报告,根据实际情况调整策略。
CSP 的局限性
1. 不完全兼容旧浏览器
旧版本浏览器可能不支持 CSP 或支持不完整。
2. 可能影响功能
严格的 CSP 策略可能阻止某些合法功能,如第三方分析工具、广告等。
3. 不能完全替代其他安全措施
CSP 不能替代输入验证、输出编码等其他安全措施。
4. 配置复杂
正确配置 CSP 需要深入理解应用程序的资源依赖关系。
实际案例
案例 1:防止存储型 XSS
javascript// 服务器端设置 CSP app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self';"); next(); }); // 即使攻击者在评论区注入了恶意脚本 // <script>alert('XSS')</script> // 浏览器也会阻止脚本执行
案例 2:防止反射型 XSS
javascript// 服务器端设置 CSP app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self';"); next(); }); // 即使攻击者构造了恶意 URL // http://example.com/search?q=<script>alert('XSS')</script> // 浏览器也会阻止脚本执行
案例 3:防止 DOM 型 XSS
javascript// 服务器端设置 CSP app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self';"); next(); }); // 即使页面中有不安全的 DOM 操作 // document.getElementById('output').innerHTML = location.hash; // 浏览器也会阻止内联脚本执行
总结
Content Security Policy 是防止 XSS 攻击的强大工具,它通过限制资源来源和阻止不安全的脚本执行,有效地减少了 XSS 攻击的风险。实施 CSP 的最佳实践包括:
- 从严格的策略开始,逐步放宽
- 避免使用 'unsafe-inline' 和 'unsafe-eval'
- 使用 nonce 或 hash 来允许特定的内联脚本
- 使用报告模式测试策略
- 定期审查和更新策略
- 将 CSP 作为多层防御策略的一部分
虽然 CSP 不能完全替代其他安全措施,但它是现代 Web 应用安全架构中不可或缺的一部分。