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