Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Brownfield 模式

_**这是默认模式。**_

这是使用 Tauri 的最简单和最直接的模式,因为本模式会尽最大可能尝试与现有的前端项目兼容。简而言之,它尽量不要求额外的配置,跟现有的 web 前端应用在浏览器中使用的方式保持一致。但并不是 _**所有**_ 在现有浏览器应用中有效的功能都会开箱即用
Brownfield 模式是使用 Tauri 最简单、最直接的方式,因为它旨在最大限度地兼容现有的前端项目。简而言之,它几乎不需要额外配置,让你能够像在浏览器中运行 Web 应用一样无缝开发。不过需要注意,**并非所有**能在浏览器中运行的功能都支持“开箱即用”

如果你不熟悉 Brownfield 软件开发模式,可以阅读 [Brownfield 维基百科]。对 Tauri 而言,现有软件特指现代浏览器支持的特性与行为规范,而非传统遗留系统。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import { CardGrid, LinkCard } from '@astrojs/starlight/components';
/>
</CardGrid>

Tauri 使用一种特定风格的进程间通信,称为[异步消息传递],其中进程通过一些简单的数据表示交换*请求*和*响应*。对于任何有 Web 开发经验的人来说,消息传递应该听起来很熟悉,因为这种范式用于互联网的客户端-服务器通信
Tauri 使用一种特定风格的进程间通信,称为[异步消息传递],进程间通过简单的数据载体交换“请求”和“响应”。对于有 Web 开发经验的人来说,消息传递机制一定不陌生,因为互联网的客户端-服务器(Client-Server)通信正是采用了这种范式

消息传递是一种比共享内存或直接函数访问更安全的技术,因为接收方可以自由地拒绝或丢弃请求。例如,如果Tauri核心进程确定某个请求是恶意的,它将简单地丢弃该请求,并且不会执行相应的函数
相比于共享内存或直接调用函数,消息传递是一种更安全的技术。因为接收方拥有主动权,可以自由地过滤或丢弃非法请求。例如,如果 Tauri 核心进程判断某个 IPC 请求具有恶意,它会直接丢弃该消息,而绝不会去执行相应的函数

接下来,我们将更详细地解释 Tauri 的两个 IPC 原语——`事件`和`命令`。

## 事件

事件是一次性、单向的 IPC 消息,最适合用于通信生命周期事件和状态变化。与[命令](#命令)不同,事件可以由前端*和* Tauri 核心发出
事件是一次性、单向的 IPC 消息,最适合用于通信生命周期事件和状态变化。与[命令](#命令)不同,事件可以由前端*和* Tauri 核心双向发起

<figure>

Expand All @@ -56,7 +56,7 @@ Core -> Frontend: "Event"{style.animated: true}

## 命令

Tauri 还提供了一种类似于[外部函数接口]的抽象,建立在IPC消息之上[^1]。主要 API `invoke` 类似于浏览器的`fetch` API,允许前端调用 Rust 函数、传递参数并接收数据。
Tauri 还提供了一种类似于[外部函数接口]的抽象,建立在IPC消息之上[^1]。核心 API `invoke` 的用法类似于浏览器的`fetch` API,允许前端调用 Rust 函数、传递参数并接收数据。

由于该机制在底层使用类似 [JSON-RPC] 的协议来序列化请求和响应,因此所有参数和返回数据必须能够序列化为 JSON。

Expand Down Expand Up @@ -86,7 +86,7 @@ Core -> Frontend: "Response"{style.animated: true}
<figcaption>命令调用中涉及的 IPC 消息。</figcaption>
</figure>

[^1]: 由于命令在底层仍然使用消息传递,因此它们没有真实 FFI 接口所面临的安全隐患
[^1]: 因为命令在底层依然遵循消息传递机制,所以它们规避了真实 FFI 接口常见的内存安全隐患

[异步消息传递]: https://en.wikipedia.org/wiki/Message_passing#Asynchronous_message_passing
[json-rpc]: https://www.jsonrpc.org
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@ i18nReady: true

## 为什么这么做

隔离模式向开发者提供一种避免程序中前端不必要或恶意地调用 Tauri Core 的机制。这一需求源自运行在前端的不受信任内容的威胁,有大量依赖的应用经常遇到这种情形。请查看 [Security: Threat Models] 来了解应用程序可能遇到的威胁的来源。
隔离模式为开发者提供了一种防御机制,防止前端意外或恶意地调用 Tauri 核心。这一需求源自运行在前端的不受信任内容的威胁,有大量依赖的应用经常遇到这种情形。请查看 [security: threat models] 来了解应用程序可能遇到的威胁的来源。

隔离模式在设计时考虑的最大的威胁模型是**开发威胁**(Development Threats)。除了许多前端构建时工具所包括的数十(甚至数百)个通常是深度嵌套的依赖,一个复杂的应用也还可能捆绑大量(通常也是深度嵌套的)依赖到最终输出
隔离模式设计的初衷是为了应对**开发环境威胁**(Development Threats)。现代前端应用除了构建工具自带的成百上千个深度嵌套依赖外,最终产物中通常也会捆绑大量复杂的第三方库

## 何时需要
## 适用场景

Tauri 强烈推荐只要有可能就使用隔离模式。因为隔离应用程序截获来自前端的***所有***信息,它*始终*可以被使用
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,然后像平常一样进行解密和读取。
隔离模式的核心在于在前端和 Tauri 核心之间注入一个安全的应用程序,用于拦截和修改传入的 IPC 消息。它利用 `<iframe>` 的沙盒功能,将 JavaScript 与主前端应用程序安全地一起运行。Tauri 在加载页面时强制执行隔离模式,强制所有对 Tauri 核心的 IPC 调用都首先通过沙盒隔离应用程序进行路由。一旦消息准备好传递给 Tauri 核心,它将使用浏览器的 [SubtleCrypto] 实现进行加密,然后传递回主前端应用程序。到达主前端应用程序后,它将直接传递给 Tauri 核心,然后像平常一样进行解密和读取。

为了确保他人无法手动读取应用程序特定版本的密钥并使用它来修改加密后的消息,每次运行应用程序时都会生成新密钥。

### IPC 消息的大致步骤
### IPC 消息流转步骤

为了更容易理解,下面列出了 IPC 消息通过隔离模式发送到 Tauri Core 时将经历的大致步骤
为了方便理解,下面列出了 IPC 消息通过隔离模式发送到 Tauri 核心时将经历的大致步骤

1. Tauri 的 IPC 处理程序收到一条消息
2. IPC 处理程序 -> 隔离应用程序
Expand All @@ -40,21 +40,21 @@ _注意:箭头(->)表示消息传递。_

### 性能影响

由于消息确实会加密,因此与 [Brownfield 模式] 相比,即使安全隔离应用程序不执行任何操作,也会产生额外的开销。除了性能敏感的应用程序(这些应用程序可能拥有精心维护且数量较少的依赖项,以保持足够的性能)外,大多数应用程序应该不会在意加密/解密 IPC 消息的运行时成本,因为它们相对较小,并且 AES-GCM 相对较快。如果你不熟悉 AES-GCM,那么在此上下文中,重要的是它是 [SubtleCrypto] 中包含的唯一身份验证模式算法,并且你可能每天都在 [TLS][transport_layer_security] 中使用它。
由于消息确实会加密,因此与 [Brownfield 模式] 相比,即使安全隔离应用程序不执行任何操作,也会产生额外的开销。除了性能敏感的应用程序(这些应用程序可能拥有精心维护且数量较少的依赖项,以保持足够的性能)外,大多数应用程序应该不会受到加密/解密 IPC 消息的运行时成本影响,因为它们相对较小,并且 AES-GCM 相对较快。如果你不熟悉 AES-GCM,那么在此上下文中,重要的是它是 [SubtleCrypto] 中包含的唯一身份验证模式算法,并且你可能每天都在 [TLS][transport_layer_security] 中使用它。

Tauri 应用程序每次启动时都会生成一个加密安全密钥。如果系统已经拥有足够的熵来立即返回足够的随机数,通常不会注意到这一点,这在桌面环境中非常常见。如果您在无头环境中运行 [WebDriver 一体化测试], 则可能需要安装某种熵生成服务(例如 `haveged` ,如果您的操作系统尚未安装该服务)。<sup>Linux 5.6(2020 年 3 月)现在包含使用推测执行的熵生成功能。</sup>
Tauri 应用程序每次启动时都会生成一个加密安全密钥。如果系统已经拥有足够的熵来立即返回足够的随机数,通常不会注意到这一点,这在桌面环境中非常常见。如果你在无头环境中运行 [WebDriver 集成测试], 则可能需要安装某种熵生成服务(例如 `haveged` ,如果你的操作系统尚未安装该服务)。<sup>Linux 5.6(2020 年 3 月)现在包含使用推测执行的熵生成功能。</sup>

### 限制

由于平台差异,隔离模式存在一些限制。最严重的限制是由于外部文件无法在 Windows 上的沙盒化 `<iframes>` 中正确加载。因此,我们在构建时实现了一个简单的脚本内联步骤,该步骤获取与隔离应用相关的脚本内容,并将其以内联方式注入。这意味着典型的打包或像 `<script src="index.js"></script>` 这样的文件简单包含仍然有效,但像 ES 模块这样的较新机制将*无法*成功加载。

## 建议

由于隔离应用程序的目的是防御开发威胁,我们强烈建议您的隔离应用程序尽可能保持简单。您不仅应该努力保持隔离应用程序的依赖关系最小化,还应该考虑尽量减少其所需的构建步骤。这样,您就无需担心前端应用程序之上的隔离应用程序受到供应链攻击
由于隔离应用程序的目的是防御开发威胁,我们强烈建议你的隔离应用程序尽可能保持简单。你不仅应该努力保持隔离应用程序的依赖关系最小化,还应该考虑尽量减少其所需的构建步骤。这样,你就无需担心前端应用程序之上的隔离应用程序受到供应链攻击

## 创建隔离应用程序

在这个例子中,我们将创建一个小型的 hello-world 风格的 Isolation 应用,并将其连接到一个虚构的现有 Tauri 应用。它不会对传入的消息进行验证,只会将内容打印到 WebView 控制台。
在这个例子中,我们将创建一个小型的 hello-world 风格的隔离模式应用,并将其连接到一个虚构的现有 Tauri 应用。它不会对传入的消息进行验证,只会将内容打印到 WebView 控制台。

为了本例的目的,假设我们与 `tauri.conf.json` 位于同一目录中。现有的 Tauri 应用程序将其 `distDir` 设置为 `../dist` 。

Expand All @@ -77,7 +77,7 @@ Tauri 应用程序每次启动时都会生成一个加密安全密钥。如果

```javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// 不需要验证或修改任何内容,仅输出钩子中的内容
// 不需要验证或修改任何内容,仅输出 Hook 中的内容
console.log('hook', payload);
return payload;
};
Expand Down Expand Up @@ -112,4 +112,4 @@ window.__TAURI_ISOLATION_HOOK__ = (payload) => {
[事件]: /zh-cn/reference/javascript/api/namespaceevent/
[subtlecrypto]: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
[brownfield 模式]: /zh-cn/concept/inter-process-communication/brownfield/
[WebDriver 一体化测试]: /zh-cn/develop/tests/webdriver/
[WebDriver 集成测试]: /zh-cn/develop/tests/webdriver/
Loading