CSP配置 #

一、CSP概述 #

1.1 什么是 CSP #

内容安全策略(Content Security Policy,CSP)是一种安全机制,用于限制网页可以加载的资源来源。

text
┌─────────────────────────────────────────────────────────────┐
│                      CSP 作用                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐                                            │
│  │   网页请求   │                                            │
│  │  加载资源   │                                            │
│  └──────┬──────┘                                            │
│         │                                                   │
│         ▼                                                   │
│  ┌─────────────┐     ┌─────────────┐                       │
│  │   CSP 检查   │────►│   允许      │───► 加载资源          │
│  └─────────────┘     └─────────────┘                       │
│         │                                                   │
│         ▼                                                   │
│  ┌─────────────┐                                           │
│  │   拒绝      │───► 阻止加载                               │
│  └─────────────┘                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 CSP 的作用 #

作用 说明
防止 XSS 阻止内联脚本执行
控制资源来源 限制资源加载来源
防止数据注入 阻止恶意内容注入
报告违规 报告 CSP 违规行为

二、CSP 配置 #

2.1 基本配置 #

json
// tauri.conf.json
{
    "app": {
        "security": {
            "csp": "default-src 'self'"
        }
    }
}

2.2 HTML meta 标签配置 #

html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

2.3 HTTP 头配置 #

rust
use tauri::Builder;

Builder::default()
    .on_page_load(|window, _payload| {
        // 设置 CSP 头
        window.eval("document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]')")
            .ok();
    });

三、CSP 指令 #

3.1 基础指令 #

指令 说明 示例
default-src 默认资源策略 default-src 'self'
script-src JavaScript 来源 script-src 'self'
style-src CSS 来源 style-src 'self'
img-src 图片来源 img-src 'self' data:
font-src 字体来源 font-src 'self'
connect-src 网络请求来源 connect-src 'self'
media-src 媒体来源 media-src 'self'
object-src 插件来源 object-src 'none'
frame-src iframe 来源 frame-src 'self'

3.2 安全指令 #

指令 说明 示例
frame-ancestors 嵌入来源 frame-ancestors 'none'
form-action 表单提交 form-action 'self'
base-uri base 标签 base-uri 'self'
upgrade-insecure-requests 升级 HTTP upgrade-insecure-requests

3.3 指令值 #

说明
'self' 同源
'none' 禁止
'unsafe-inline' 允许内联
'unsafe-eval' 允许 eval
data: data URI
https: HTTPS 来源
* 任意来源

四、配置示例 #

4.1 严格 CSP #

json
{
    "csp": "default-src 'self'; " +
           "script-src 'self'; " +
           "style-src 'self'; " +
           "img-src 'self' data:; " +
           "font-src 'self'; " +
           "connect-src 'self'; " +
           "frame-ancestors 'none'; " +
           "form-action 'self'; " +
           "base-uri 'self'"
}

4.2 允许 CDN #

json
{
    "csp": "default-src 'self'; " +
           "script-src 'self' https://cdn.jsdelivr.net; " +
           "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
           "font-src 'self' https://fonts.gstatic.com; " +
           "img-src 'self' data: https:; " +
           "connect-src 'self' https://api.example.com"
}

4.3 开发环境 CSP #

json
{
    "csp": "default-src 'self'; " +
           "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
           "style-src 'self' 'unsafe-inline'; " +
           "connect-src 'self' ws://localhost:*"
}

4.4 条件 CSP #

rust
fn get_csp() -> String {
    #[cfg(debug_assertions)]
    {
        "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'".to_string()
    }
    
    #[cfg(not(debug_assertions))]
    {
        "default-src 'self'; script-src 'self'".to_string()
    }
}

五、常见问题解决 #

5.1 内联脚本 #

html
<!-- ❌ 被 CSP 阻止 -->
<button onclick="doSomething()">Click</button>

<!-- ✅ 使用事件监听 -->
<button id="btn">Click</button>
<script src="app.js"></script>
javascript
// app.js
document.getElementById('btn').addEventListener('click', doSomething);

5.2 内联样式 #

html
<!-- ❌ 被 CSP 鑫止 -->
<div style="color: red;">Text</div>

<!-- ✅ 使用 class -->
<div class="red-text">Text</div>
css
/* styles.css */
.red-text {
    color: red;
}

5.3 动态脚本 #

javascript
// ❌ 被 CSP 阻止
eval('console.log("hello")');

// ✅ 使用 Function
new Function('console.log("hello")')();

// 或使用 nonce
// <script nonce="abc123">...</script>

5.4 外部资源 #

html
<!-- ❌ 被 CSP 阻止 -->
<img src="https://example.com/image.png">

<!-- ✅ 配置 CSP 允许 -->
<!-- img-src 'self' https://example.com -->
<img src="https://example.com/image.png">

六、Nonce 和 Hash #

6.1 使用 Nonce #

rust
use rand::Rng;

fn generate_nonce() -> String {
    let mut rng = rand::thread_rng();
    let nonce: [u8; 16] = rng.gen();
    base64::encode(&nonce)
}
html
<script nonce="abc123">
    console.log('Hello');
</script>
json
{
    "csp": "script-src 'self' 'nonce-abc123'"
}

6.2 使用 Hash #

html
<script>
    console.log('Hello');
</script>
bash
# 生成 hash
echo -n "console.log('Hello');" | sha256sum | base64
json
{
    "csp": "script-src 'self' 'sha256-xxxxx'"
}

七、CSP 报告 #

7.1 启用报告 #

json
{
    "csp": "default-src 'self'; report-uri /csp-report"
}

7.2 报告格式 #

json
{
    "csp-report": {
        "document-uri": "http://example.com/",
        "referrer": "",
        "violated-directive": "script-src",
        "effective-directive": "script-src",
        "original-policy": "default-src 'self'",
        "blocked-uri": "http://evil.com/script.js",
        "status": 200
    }
}

八、最佳实践 #

8.1 渐进式 CSP #

javascript
// 开发阶段:宽松 CSP
const devCSP = "default-src 'self' 'unsafe-inline' 'unsafe-eval'";

// 生产阶段:严格 CSP
const prodCSP = "default-src 'self'; script-src 'self'";

8.2 CSP 检查工具 #

bash
# 使用 CSP 检查工具
npx csp-checker https://your-app.com

8.3 CSP 配置清单 #

markdown
□ 使用 'self' 作为默认来源
□ 禁用 'unsafe-inline' 和 'unsafe-eval'
□ 限制外部资源来源
□ 设置 frame-ancestors
□ 设置 form-action
□ 测试所有功能
□ 监控 CSP 报告

九、总结 #

9.1 核心要点 #

要点 说明
default-src 默认资源策略
script-src 脚本来源控制
避免不安全值 不使用 unsafe-*
使用 nonce/hash 允许特定内联
测试验证 确保功能正常

9.2 下一步 #

现在你已经掌握了 CSP 配置,接下来让我们学习 安全最佳实践,了解 Tauri 开发的安全建议!

最后更新:2026-03-28