隔离模式
隔离模式是一种在前端发送到 Tauri 核心之前拦截和修改 Tauri API 消息的方法,所有操作均使用 JavaScript 完成。由隔离模式注入的安全 JavaScript 代码称为隔离应用。
🌐 The Isolation pattern is a way to intercept and modify Tauri API messages sent by the frontend before they get to Tauri Core, all with JavaScript. The secure JavaScript code that is injected by the Isolation pattern is referred to as the Isolation application.
🌐 Why
隔离模式的目的是为开发者提供一种机制,以帮助保护其应用免受来自前端对 Tauri Core 的不必要或恶意调用。隔离模式的需求源于来自前端运行的不受信内容的威胁,对于依赖较多的应用来说,这是一个常见情况。有关应用可能面临的许多威胁来源列表,请参见 [安全性:威胁模型]。
🌐 The Isolation pattern’s purpose is to provide a mechanism for developers to help protect their application from unwanted or malicious frontend calls to Tauri Core. The need for the Isolation pattern rose out of threats coming from untrusted content running on the frontend, a common case for applications with many dependencies. See Security: Threat Models for a list of many sources of threats that an application may see.
上述描述的隔离模式设计时所考虑的最大威胁模型是开发威胁。不仅许多前端构建时工具包含数十个(甚至数百个)往往深度嵌套的依赖,而且复杂的应用也可能有大量(同样往往深度嵌套的)依赖被打包到最终输出中。
🌐 The largest threat model described above that the Isolation pattern was designed in mind was Development Threats. Not only do many frontend build-time tools consist of many dozen (or hundreds) of often deeply-nested dependencies, but a complex application may also have a large amount of (also often deeply-nested) dependencies that are bundled into the final output.
🌐 When
Tauri 强烈建议在任何可以使用的情况下使用隔离模式。因为隔离应用会拦截来自前端的 所有 消息,所以它可以 始终 使用。
🌐 Tauri highly recommends using the isolation pattern whenever it can be used. Because the Isolation application intercepts all messages from the frontend, it can always be used.
Tauri 还强烈建议每当你使用外部 Tauri API 时锁定你的应用。作为开发者,你可以利用安全隔离应用来尝试验证 IPC 输入,以确保它们在某些预期参数范围内。例如,你可能需要检查对文件的读取或写入调用,确保它没有尝试访问应用预期位置之外的路径。另一个例子是确保 Tauri API 的 HTTP fetch 调用只将 Origin 头设置为你的应用期望的值。
🌐 Tauri also strongly suggests locking down your application whenever you use external Tauri APIs. As the developer, you can utilize the secure Isolation application to try and verify IPC inputs, to make sure they are within some expected parameters. For example, you may want to check that a call to read or write a file is not trying to access a path outside your application’s expected locations. Another example is making sure that a Tauri API HTTP fetch call is only setting the Origin header to what your application expects it to be.
也就是说,它会拦截来自前端的_所有_消息,因此即使用于始终在线的 API(如 Events)也能工作。由于某些事件可能会导致你自己的 Rust 代码执行操作,因此同样类型的验证技术也可以用于这些事件。
🌐 That said, it intercepts all messages from the frontend, so it will even work with always-on APIs such as Events. Since some events may cause your own rust code to perform actions, the same sort of validation techniques can be used with them.
🌐 How
隔离模式完全是关于在你的前端和 Tauri 核心之间注入一个安全应用,以拦截和修改传入的 IPC 消息。它通过使用 <iframe> 的沙箱功能,在主前端应用旁边安全地运行 JavaScript 来实现这一点。Tauri 在加载页面时会强制执行隔离模式,迫使所有对 Tauri 核心的 IPC 调用首先通过沙箱隔离的应用进行路由。一旦消息准备好传递给 Tauri 核心,它会使用浏览器的 SubtleCrypto 实现进行加密,然后传回主前端应用。一旦到达那里,它会直接传递给 Tauri 核心,在那里被解密并像平常一样读取。
🌐 The Isolation pattern is all about injecting a secure application in between your frontend and Tauri Core to intercept and modify incoming IPC messages. It does this by using the sandboxing feature of <iframe>s to run the JavaScript securely alongside the main frontend application. Tauri enforces the Isolation pattern while loading the page, forcing all IPC calls to Tauri Core to instead be routed through the sandboxed Isolation application first. Once the message is ready to be passed to Tauri Core, it is encrypted using the browser’s SubtleCrypto implementation and passed back to the main frontend application. Once there, it is directly passed to Tauri Core, where it is then decrypted and read like normal.
为了确保某人无法手动读取应用特定版本的密钥并在加密后使用该密钥修改消息,每次运行你的应用时都会生成新密钥。
🌐 To ensure that someone cannot manually read the keys for a specific version of your application and use that to modify the messages after being encrypted, new keys are generated each time your application is run.
🌐 Approximate Steps of an IPC Message
为了更容易理解,这里有一个有序列表,其中列出了 IPC 消息在使用隔离模式发送到 Tauri Core 时将经历的大致步骤:
🌐 To make it easier to follow, here’s an ordered list with the approximate steps an IPC message will go through when being sent to Tauri Core with the Isolation pattern:
- Tauri 的 IPC 处理程序收到一条消息
- IPC 处理程序 -> 隔离应用
[sandbox]隔离应用钩子运行并可能修改消息[sandbox]消息使用运行时生成的密钥通过 AES-GCM 加密[encrypted]隔离应用 -> IPC 处理程序[encrypted]IPC 处理程序 -> Tauri 核心
注意:箭头(->)表示消息传递。
🌐 Note: Arrows (->) indicate message passing.
🌐 Performance Implications
由于消息确实进行了加密,因此与[Brownfield模式]相比,会有额外的开销,即使安全隔离应用本身没有执行任何操作。除了对性能敏感的应用(它们可能维护着一套小而精的依赖,以保持性能足够)之外,大多数应用不应注意到加密/解密IPC消息的运行时成本,因为这些成本相对较小,而AES-GCM的速度相对较快。如果你不熟悉AES-GCM,在此上下文中相关的只是它是唯一包含在SubtleCrypto中的认证模式算法,而且你很可能每天在后台与传输层安全一起使用它。
🌐 Because encryption of the message does occur, there are additional overhead costs compared to the Brownfield pattern, even if the secure Isolation application doesn’t do anything. Aside from performance-sensitive applications (who likely have a carefully-maintained and small set of dependencies, to keep the performance adequate), most applications should not notice the runtime costs of encrypting/decrypting the IPC messages, as they are relatively small and AES-GCM is relatively fast. If you are unfamiliar with AES-GCM, all that is relevant in this context is that it’s the only authenticated mode algorithm included in SubtleCrypto and that you probably already use it every day under the hood with TLS.
每次启动 Tauri 应用时,也会生成一个加密安全的密钥。如果系统已经有足够的熵来立即返回足够的随机数,这通常在桌面环境中非常常见,那么这通常是不会被注意到的。如果在无头环境中运行以执行一些【使用 WebDriver 的集成测试】,那么如果你的操作系统没有自带熵生成服务,你可能需要安装某种熵生成服务,例如 haveged。 Linux 5.6(2020 年 3 月)现在包括使用推测执行的熵生成。
🌐 Limitations
There are a few limitations in the Isolation pattern that arose out of platform inconsistencies. The most significant limitation is due to external files not loading correctly inside sandboxed <iframes> on Windows. Because of this, we have implemented a simple script inlining step during build time that takes the content of scripts relative to the Isolation application and injects them inline. This means that typical bundling or simple including of files like <script src="index.js"></script> still works properly, but newer mechanisms such as ES Modules will not successfully load.
🌐 Recommendations
因为隔离应用的目的是防止开发威胁,我们强烈建议尽可能保持你的隔离应用的简单。你不仅应该努力将隔离应用的依赖保持最小化,还应考虑尽量减少其所需的构建步骤。这将使你无需在关注前端应用的同时,还担心对隔离应用的供应链攻击。
🌐 Because the point of the Isolation application is to protect against Development Threats, we highly recommend keeping your Isolation application as simple as possible. Not only should you strive to keep dependencies of your isolation application minimal, but you should also consider keeping its required build steps minimal. This would allow you to not need to worry about supply chain attacks against your Isolation application on top of your frontend application.
🌐 Creating the Isolation Application
在这个例子中,我们将制作一个小型的 hello-world 风格的 Isolation 应用,并将其连接到一个假想的现有 Tauri 应用。它不会对传递的消息进行任何验证,只会将内容打印到 WebView 控制台。
🌐 In this example, we will make a small hello-world style Isolation application and hook it up to an imaginary existing Tauri application. It will do no verification of the messages passing through it, only print the contents to the WebView console.
为了这个示例的目的,假设我们位于与 tauri.conf.json 相同的目录中。现有的 Tauri 应用的 frontendDist 设置为 ../dist。
🌐 For the purposes of this example, let’s imagine we are in the same directory as tauri.conf.json. The existing Tauri application has its frontendDist set to ../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 模式] 引导到隔离模式。
🌐 Now, all we need to do is set up our tauri.conf.json configuration to use the Isolation pattern, and have just bootstrapped to the Isolation pattern from the Brownfield pattern.
🌐 Configuration
假设我们的主要前端 frontendDist 被设置为 ../dist。我们也将隔离应用输出到 ../dist-isolation。
🌐 Let’s assume that our main frontend frontendDist is set to ../dist. We also output our Isolation application to ../dist-isolation.
{ "build": { "frontendDist": "../dist" }, "app": { "security": { "pattern": { "use": "isolation", "options": { "dir": "../dist-isolation" } } } }}Tauri 中文网 - 粤ICP备13048890号
Nodejs.cn 旗下网站