隔离模式
隔离模式是一种在前端发送的 Tauri API 消息到达 Tauri Core 之前拦截和修改它们的方法,所有这些都使用 JavaScript 完成。由隔离模式注入的安全 JavaScript 代码称为隔离应用程序。
为什么
隔离模式的目的是为开发者提供一种机制,以帮助保护他们的应用程序免受来自前端对 Tauri Core 的意外或恶意调用。对隔离模式的需求源于来自前端运行的不可信内容的威胁,这对于具有许多依赖项的应用程序来说是一个常见情况。请参阅 安全性:威胁模型,了解应用程序可能面临的许多威胁来源。
上面描述的最主要的威胁模型,隔离模式的设计就是为了应对开发威胁。许多前端构建时工具不仅包含数十个(或数百个)通常深度嵌套的依赖项,而且复杂的应用程序还可能包含大量(也通常深度嵌套的)依赖项,这些依赖项被捆绑到最终输出中。
何时
Tauri 强烈建议在任何可以使用隔离模式的情况下使用它。因为隔离应用程序拦截了来自前端的所有消息,所以它始终可以使用。
Tauri 还强烈建议在使用外部 Tauri API 时锁定您的应用程序。作为开发者,您可以利用安全的隔离应用程序来尝试验证 IPC 输入,以确保它们在某些预期参数范围内。例如,您可能希望检查读取或写入文件的调用是否未尝试访问应用程序预期位置之外的路径。另一个示例是确保 Tauri API HTTP 获取调用仅将 Origin 标头设置为您的应用程序期望的值。
也就是说,它拦截了来自前端的所有消息,因此它甚至可以与始终开启的 API(例如 事件)一起使用。由于某些事件可能会导致您自己的 Rust 代码执行操作,因此可以对它们使用相同的验证技术。
如何
隔离模式的核心是在前端和 Tauri Core 之间注入一个安全的应用程序,以拦截和修改传入的 IPC 消息。它通过使用<iframe>
的沙盒功能来实现,以便与主前端应用程序一起安全地运行 JavaScript。Tauri 在加载页面时强制执行隔离模式,强制所有对 Tauri Core 的 IPC 调用首先通过沙盒化的隔离应用程序进行路由。一旦消息准备好传递到 Tauri Core,它将使用浏览器的 SubtleCrypto 实现进行加密,然后传递回主前端应用程序。在那里,它直接传递到 Tauri Core,然后在那里解密并像正常一样读取。
为了确保没有人能够手动读取特定应用程序版本的密钥并使用它来修改加密后的消息,每次运行应用程序时都会生成新的密钥。
IPC 消息的近似步骤
为了便于理解,这里列出了使用隔离模式将 IPC 消息发送到 Tauri Core 时将经历的近似步骤。
- Tauri 的 IPC 处理程序接收一条消息
- IPC 处理程序 -> 隔离应用程序
[沙盒]
隔离应用程序钩子运行并可能修改消息[沙盒]
使用运行时生成的密钥使用 AES-GCM 加密消息[加密]
隔离应用程序 -> IPC 处理程序[加密]
IPC 处理程序 -> Tauri Core
注意:箭头 (->) 表示消息传递。
性能影响
由于确实会对消息进行加密,因此与 Brownfield 模式 相比,即使安全的隔离应用程序什么也不做,也会产生额外的开销。除了对性能敏感的应用程序(它们可能拥有经过仔细维护且依赖项较小的集合,以保持足够的性能)之外,大多数应用程序都不应该注意到加密/解密 IPC 消息的运行时成本,因为它们相对较小,而且 AES-GCM 相对较快。如果您不熟悉 AES-GCM,那么在此上下文中相关的只是它是 SubtleCrypto 中包含的唯一经过身份验证的模式算法,而且您可能每天都在幕后使用它 TLS。
每次启动 Tauri 应用程序时还会生成一个加密安全的密钥。如果系统已经有足够的熵可以立即返回足够的随机数,这在桌面环境中非常常见,则通常不会注意到。如果在无头环境中运行以执行一些 使用 WebDriver 进行集成测试,那么如果您的操作系统没有包含熵生成服务,则可能需要安装某种熵生成服务,例如haveged
。Linux 5.6(2020 年 3 月)现在包含使用推测执行的熵生成。
局限性
隔离模式中存在一些由于平台不一致而产生的局限性。最主要的限制是由于外部文件在 Windows 上的沙盒化<iframes>
中无法正确加载。因此,我们在构建时实现了一个简单的脚本内联步骤,该步骤获取相对于隔离应用程序的脚本内容并将其内联注入。这意味着典型的捆绑或简单的包含文件(如<script src="index.js"></script>
)仍然可以正常工作,但 ES 模块等较新的机制将无法成功加载。
建议
由于隔离应用程序的目的是为了防止开发威胁,我们强烈建议您使隔离应用程序尽可能简单。您不仅应该努力使依赖项最小化,还应该考虑使所需的构建步骤最小化。这将使您无需担心除了前端应用程序之外,还要担心针对隔离应用程序的供应链攻击。
创建隔离应用程序
在此示例中,我们将创建一个小型“hello-world”样式的隔离应用程序,并将其连接到一个虚构的现有 Tauri 应用程序。它不会验证通过它的消息,只会将内容打印到 WebView 控制台。
出于本示例的目的,让我们假设我们位于与tauri.conf.json
相同的目录中。现有 Tauri 应用程序将其distDir
设置为../dist
。
../dist-isolation/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
../dist-isolation/index.js
:
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// let's not verify or modify anything, just print the content from the hook
console.log('hook', payload)
return payload
}
现在,我们只需设置我们的tauri.conf.json
配置 以使用隔离模式,并从 Brownfield 模式 启动到隔离模式。
配置
让我们假设我们的主前端distDir
设置为../dist
。我们还将隔离应用程序输出到../dist-isolation
。
{
"build": {
"distDir": "../dist"
},
"tauri": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../dist-isolation"
}
}
}
}