乐闻世界logo
搜索文章和话题

什么是 Content Security Policy(CSP)?如何使用 CSP 防止 XSS 攻击?

2月21日 16:27

答案

Content Security Policy(CSP,内容安全策略)是一种强大的安全机制,用于防止 XSS 攻击、数据注入攻击和其他类型的代码注入攻击。CSP 通过限制浏览器可以加载和执行的资源来源,有效地减少了攻击面。

CSP 的核心概念

定义: CSP 是一个 HTTP 响应头,它告诉浏览器哪些资源(如脚本、样式、图片、字体等)可以从哪些来源加载。通过定义白名单,CSP 可以防止恶意脚本的执行。

基本语法:

shell
Content-Security-Policy: <policy-directive>; <policy-directive>; ...

CSP 的主要指令

1. default-src

设置所有资源类型的默认策略。如果没有为特定资源类型设置策略,则使用 default-src 的值。

shell
Content-Security-Policy: default-src 'self';

2. script-src

控制 JavaScript 脚本的来源。

shell
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;

3. style-src

控制 CSS 样式表的来源。

shell
Content-Security-Policy: style-src 'self' 'unsafe-inline';

4. img-src

控制图片的来源。

shell
Content-Security-Policy: img-src 'self' data: https:;

5. connect-src

控制 XMLHttpRequest、WebSocket、EventSource 等连接的来源。

shell
Content-Security-Policy: connect-src 'self' https://api.example.com;

6. font-src

控制字体的来源。

shell
Content-Security-Policy: font-src 'self' https://fonts.gstatic.com;

7. object-src

控制 <object><embed><applet> 等元素的来源。

shell
Content-Security-Policy: object-src 'none';

8. media-src

控制 <audio><video> 等媒体元素的来源。

shell
Content-Security-Policy: media-src 'self' https://media.example.com;

9. frame-src

控制 <frame><iframe> 等框架元素的来源。

shell
Content-Security-Policy: frame-src 'self' https://trusted-iframe.com;

10. base-uri

限制 <base> 元素可以使用的 URL。

shell
Content-Security-Policy: base-uri 'self';

11. form-action

限制表单可以提交的目标 URL。

shell
Content-Security-Policy: form-action 'self';

12. frame-ancestors

限制哪些页面可以将当前页面嵌入到 <frame><iframe> 中。

shell
Content-Security-Policy: frame-ancestors 'none';

CSP 的源值

1. 'self'

只允许从同源加载资源。

shell
Content-Security-Policy: default-src 'self';

2. 'none'

不允许从任何来源加载资源。

shell
Content-Security-Policy: object-src 'none';

3. 'unsafe-inline'

允许内联脚本和样式(不推荐使用)。

shell
Content-Security-Policy: script-src 'self' 'unsafe-inline';

4. 'unsafe-eval'

允许使用 eval() 和类似的函数(不推荐使用)。

shell
Content-Security-Policy: script-src 'self' 'unsafe-eval';

5. 'strict-dynamic'

允许由可信脚本加载的脚本执行。

shell
Content-Security-Policy: script-src 'self' 'strict-dynamic';

6. 'report-sample'

在违规报告中包含样本代码。

shell
Content-Security-Policy: script-src 'self' 'report-sample';

7. 具体域名

允许从特定域名加载资源。

shell
Content-Security-Policy: script-src 'self' https://cdn.example.com;

8. 通配符

允许从任何子域名加载资源。

shell
Content-Security-Policy: script-src 'self' https://*.example.com;

9. 协议限定

允许从特定协议加载资源。

shell
Content-Security-Policy: img-src https:;

CSP 如何防止 XSS 攻击

1. 阻止内联脚本执行

不安全的页面:

html
<script> alert('XSS'); </script>

使用 CSP 防护:

shell
Content-Security-Policy: script-src 'self';

结果: 内联脚本将被阻止执行。

2. 阻止 eval 执行

不安全的代码:

javascript
eval('alert("XSS")');

使用 CSP 防护:

shell
Content-Security-Policy: script-src 'self';

结果: eval() 调用将被阻止。

3. 限制外部脚本来源

不安全的页面:

html
<script src="https://malicious.com/script.js"></script>

使用 CSP 防护:

shell
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;

结果: 来自恶意域名的脚本将被阻止加载。

4. 阻止动态脚本注入

不安全的代码:

javascript
const script = document.createElement('script'); script.src = 'https://malicious.com/script.js'; document.body.appendChild(script);

使用 CSP 防护:

shell
Content-Security-Policy: script-src 'self';

结果: 动态注入的脚本将被阻止加载。

CSP 的实施方式

1. 通过 HTTP 响应头

Node.js Express 示例:

javascript
app.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 配置示例:

nginx
add_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 配置示例:

apache
Header 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)来测试策略,而不会阻止任何资源加载。

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

报告端点示例:

javascript
app.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. 从严格策略开始

shell
Content-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. 逐步放宽策略

根据实际需求逐步添加允许的来源。

shell
Content-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'

不推荐:

shell
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval';

推荐:

shell
Content-Security-Policy: script-src 'self' 'nonce-abc123';

4. 使用 nonce 或 hash

Nonce 示例:

html
<script nonce="abc123"> // 这个脚本将被允许执行 </script>
shell
Content-Security-Policy: script-src 'self' 'nonce-abc123';

Hash 示例:

html
<script> alert('Hello'); </script>
shell
Content-Security-Policy: script-src 'self' 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=';

5. 使用 report-uri 监控违规

shell
Content-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 的最佳实践包括:

  1. 从严格的策略开始,逐步放宽
  2. 避免使用 'unsafe-inline' 和 'unsafe-eval'
  3. 使用 nonce 或 hash 来允许特定的内联脚本
  4. 使用报告模式测试策略
  5. 定期审查和更新策略
  6. 将 CSP 作为多层防御策略的一部分

虽然 CSP 不能完全替代其他安全措施,但它是现代 Web 应用安全架构中不可或缺的一部分。

标签:XSS