内容安全策略(CSP)
本教程共 48 篇 · 第 40 篇 · 更新于 2026-08-09 · 约 10 分钟阅读
本节目标:读完你能看懂 CSP 各条指令的含义,在
tauri.conf.json里写出合理的 CSP 配置,并理解 Tauri 自动注入 nonce 和 hash 的机制。
如果你的前端页面被注入了一段恶意脚本(XSS 攻击),这段脚本能做什么?没有 CSP 的话,它能发网络请求、能加载外部资源、能执行任意 JS。CSP(Content Security Policy,内容安全策略)就是给 WebView 画一道框——哪些来源的脚本可以执行、哪些来源的图片可以加载、能连哪些网络地址,都由 CSP 说了算。
CSP 是什么
CSP 本来是 Web 标准里的安全机制,浏览器用它来限制页面能加载哪些资源。Tauri 的 WebView 也支持 CSP,而且 Tauri 在编译时会自动帮你做一部分工作——本地脚本会被计算哈希,外部脚本会被分配 nonce(一次性随机数),让合法脚本正常加载、非法脚本被挡掉。
CSP 在 Tauri 中不是默认开启的。你需要在 tauri.conf.json 里显式配置,它才生效。
在 tauri.conf.json 中配置 CSP
CSP 配置写在 app.security.csp 字段里。可以写成字符串,也可以写成对象(按指令分别设置):
// 字符串形式
{
"app": {
"security": {
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost"
}
}
}
// 对象形式
{
"app": {
"security": {
"csp": {
"default-src": "'self' customprotocol: asset:",
"connect-src": "ipc: http://ipc.localhost",
"font-src": ["https://fonts.gstatic.com"],
"img-src": "'self' asset: http://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com"
}
}
}
}
两种写法效果一样,对象形式更易读,适合多指令的场景。
常用 CSP 指令解读
CSP 由多条指令组成,每条指令控制一类资源的加载策略。以下是 Tauri 应用中最常用的几条:
default-src 是兜底指令——其他指令没明确配置的资源类型,都走 default-src 的规则。'self' 表示只允许加载同源资源(即应用自带的文件)。这是最基础的一道防线。
connect-src 控制能连哪些网络地址。Tauri 应用里必须包含 ipc: http://ipc.localhost,否则前端无法通过 IPC 和后端通信——这是 Tauri 特有的。
script-src 控制能执行哪些脚本。Tauri 会在编译时自动给本地脚本加 hash、给外部脚本加 nonce,你一般不需要手动配。但如果你的前端用了 WebAssembly,要加上 'wasm-unsafe-eval'。
style-src 控制能加载哪些样式。如果用了内联样式(很多 UI 框架会注入),需要 'unsafe-inline'。
img-src 控制能加载哪些图片。data: 允许 base64 图片,blob: 允许 Blob URL 图片。
font-src 控制能加载哪些字体文件。如果用了 Google Fonts,需要允许 https://fonts.gstatic.com。
Note
'self'中的引号是 CSP 语法的一部分,不是字符串引号。在 JSON 里写'self'时,整个值是字符串"default-src 'self'",'self'是其中的一个 source 关键字。
nonce 与 hash 自动注入
你可能会想:我配了 script-src 'self',那内联的 <script> 标签不就被拦了吗?没错,CSP 默认不允许内联脚本。但 Tauri 帮你解决了这个问题。
在编译时,Tauri 会扫描 HTML 中的内联脚本,计算它们的 SHA-256 哈希值,然后自动追加到 CSP 的 script-src 里。对于外部引用的脚本和样式文件,Tauri 会生成一个随机的 nonce(number used once),附加到资源标签上,同时在 CSP 中允许这个 nonce。
你不需要手动做任何事——Tauri 在构建时全自动处理。你配的 CSP 是「你自己应用的额外规则」,Tauri 的自动注入是在你的配置基础上「追加」的。
编译后的 HTML 里,你可能会看到类似这样的结果:
content-security-policy: default-src 'self'; connect-src ipc: http://ipc.localhost; script-src 'self' 'sha256-Wjjrs6qinmnr+tOry8x8PPwI77eGpUFR3EEGZktjJNs='
那个 sha256-... 就是 Tauri 自动算出来的内联脚本哈希。
一个推荐的 CSP 模板
对于大多数 Tauri 应用,以下 CSP 配置是一个比较合理的起点:
{
"app": {
"security": {
"csp": {
"default-src": "'self'",
"connect-src": "ipc: http://ipc.localhost",
"img-src": "'self' asset: http://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self'"
}
}
}
}
这个模板做了几件事:
default-src 'self':默认只允许加载同源资源connect-src保留 IPC 通道,前端能和后端通信img-src允许 Tauri 资源协议、Blob 和 base64 图片style-src允许内联样式(大多数 UI 框架需要)
如果你的前端用了 WebAssembly,加上 script-src:
"script-src": "'self' 'wasm-unsafe-eval'"
TipCSP 配置没有「标准答案」,取决于你的应用实际加载了哪些资源。最稳妥的做法是:先配一个严格的 CSP,然后跑应用看控制台报什么 CSP 违规错误,根据错误逐步放开需要的资源来源。这叫「白名单模式」——从最紧开始放,而不是从最松开始收。
避免加载远程内容
CSP 最重要的一条实践:尽量不要从远程 CDN 加载脚本。
// 不推荐:依赖远程 CDN
"script-src": "'self' https://cdn.jsdelivr.net"
// 推荐:把资源下载到本地
"script-src": "'self'"
原因很直接——CDN 被入侵或域名过期被抢注后,攻击者可以替换你的脚本,这是真实的攻击向量。把第三方库下载到本地、打包进应用,是更安全的做法。
Warning如果你必须加载远程资源(比如连后端 API),确保走 HTTPS,并在 CSP 中明确指定域名。绝不要用通配符
*放开所有来源——这等于没配 CSP。
HTTP 安全头
除了 CSP,Tauri 还支持配置其他 HTTP 安全响应头。这些头会随 WebView 的响应一起发送:
{
"app": {
"security": {
"headers": {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "require-corp",
"X-Content-Type-Options": "nosniff"
},
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost"
}
}
}
注意 CSP 不放在 headers 里,它有独立的 csp 字段。headers 里支持的头部名称是有限制的,包括 CORS 相关头、COOP、COEP、CORP 等,但不包含 CSP。
Note开发环境下,前端框架(Vite、Angular 等)的 dev server 会注入自己的 HTTP 头。Tauri 只能在构建产物中注入头,不能注入到 dev server 的响应里。所以某些安全头在开发时可能不生效,构建后才会正常工作。如果需要开发时也生效,要同时在前端框架的配置里加对应的头。
小结
CSP 是 Tauri 安全模型的「前端防线」,限制 WebView 能加载和执行哪些资源。在 tauri.conf.json 的 app.security.csp 中配置,支持字符串和对象两种写法。Tauri 在编译时自动为内联脚本计算 hash、为外部脚本生成 nonce,追加到 CSP 中——你只需配置应用特有的规则。推荐从严格配置开始,按需逐步放开。最关键的实践是避免加载远程 CDN 脚本,把第三方资源下载到本地打包。此外还可以通过 app.security.headers 配置 COOP、COEP 等安全头,和 CSP 一起构成多层防护。