在 Tauri 中,内容安全策略(CSP)是加固前端安全的核心防线,尤其在 WebView 环境中,CSP 几乎是你抵御 XSS 和数据注入攻击的唯一内置屏障。然而,实际开发中经常看到一些配置错误,不仅让 CSP 形同虚设,还可能导致应用功能异常。
1. 默认放开所有来源:default-src *
错误现象
为了方便,直接将 CSP 设为 default-src 或 default-src 'unsafe-inline' 'unsafe-eval' 。这等于完全关闭了 CSP 的保护,任何内联脚本、远程资源都可以执行。
风险和后果
一旦前端页面的任何一处存在 DOM XSS 漏洞,攻击者可以自由加载外部脚本并执行,访问 Tauri 的 IPC 接口(如果你还错误地允许了全部命令),甚至可以调用原生 API 进行恶意操作。
正确做法
- 永远将
default-src设置为最小权限,例如'self'。 - 如果确实需要加载外部资源(如 CDN 字体、图片),单独指定
font-src、img-src等指令,限制到具体域名。 - 内联脚本和样式通常应避免,如果必须使用,使用
'nonce-...'或'sha256-...'哈希替代'unsafe-inline'。
2. 忘记添加 'nonce' 导致内联代码完全阻止
错误现象
很多 UI 框架(如 Vue、React)会在 HTML 中内联一小段初始化脚本。如果在 CSP 中只写了 script-src 'self',这些内联脚本会被阻止,页面出现空白或报错。
避免方法
- 尽量将启动逻辑提取到外部
.js文件中加载。 - 如果必须内联,在 HTML 的
<script>标签上添加nonce属性,并在 Tauri 配置的 CSP 中写入script-src 'self' 'nonce-{随机值}'。每次页面加载时 nonce 必须随机生成,且不能重复使用。
3. 混淆开发环境与生产环境的 CSP
错误现象
开发时为了方便,开启了 'unsafe-eval'(Vue 等框架需要 eval 做热重载)和 'unsafe-inline',结果生产版本忘记收紧,直接保留了这些危险配置。
规避策略
- 使用环境变量区分开发和构建时的 CSP。开发时允许 eval,构建后自动移除。
- 在打包前利用脚本检查最终 HTML 中的 CSP 标签,确保不包含
unsafe-eval和不必要的unsafe-inline。 - Tauri 可以在
tauri.conf.json中配置security.csp,这个 CSP 会施加到所有页面,是最后的防线,务必保持收紧。
4. 遗漏了 connect-src,导致 API 请求或 WebSocket 断连
错误现象
设置了严格的 default-src 'self',但前端需要通过 fetch 调用本地 Rust 命令(实质上是 IPC 请求)或连接某些远程接口。由于未设置 connect-src,这些请求会被 CSP 阻挡,控制台报错 Refused to connect。
解决方法
- 明确添加
connect-src 'self' https://your-api.com,将你所有需要请求的源加进来。 - 注意 Tauri 的 IPC 调用使用的是
tauri://localhost或自定义协议,需要添加到 CSP 中:connect-src 'self' tauri: https://your-api.com。
5. 错误的 frame-src 导致 iframe 内容无法加载
错误现象
应用中嵌入了一个 iframe 显示外部网页,但 CSP 默认没有 frame-src 指令,浏览器会回退使用 default-src,导致 iframe 资源被阻止。
修复
- 显式设置
frame-src https://trusted.site,仅允许你信任的源嵌入。避免使用通配符。
6. 依赖 HTTP 头 CSP 而忽略 meta 标签
在 Tauri 中,前端页面通常是通过本地文件或自定义协议加载的,服务器响应头可能不可控。很多开发者会忘记在 HTML 中使用 <meta http-equiv="Content-Security-Policy" content="..."> 来设置 CSP,导致策略未生效。
最佳实践
- 在
index.html中始终放置一个最小化的 CSP meta 标签。 - Tauri 的
tauri.conf.json中的security.csp会覆盖 HTML 中的 meta,可以用来设定全局策略,但也要确保 HTML 有基本策略以防止配置失误。
7. 使用 'strict-dynamic' 时的错误理解
'strict-dynamic' 可以动态信任由已受信脚本加载的其他脚本,但如果不了解它的规则,可能会误以为它自动放行所有脚本。实际上 'strict-dynamic' 会忽略基于 URL 的主机白名单,只信任通过 nonce 或哈希验证的脚本所加载的子脚本。如果同时使用了 'unsafe-inline','strict-dynamic' 会被忽略。
使用建议
仅在确实需要动态脚本加载且已全面使用 nonce 的场景下使用。大多数 Tauri 应用不需要它。
总结:CSP 配置没有“一刀切”的方案,但遵循“最小权限、精确来源、不去生产环境留后门”的原则,可以让你既保持安全又不影响功能。每次修改前端或添加新依赖后,都应在浏览器 DevTools 的 Security 面板检查是否有 CSP 违规报告,及时修正。