第 11 章 网络组装系统接口(WASI)
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
我来到这个世界不是为了满足你的期望,你来到这个世界也不是为了满足我的期望。
李小龙
在 WebAssembly 中,有些事情会变得不必要的困难,这是因为在其他平台上更容易实现的安全性目标。在 C、C++ 或 Rust 等语言中,从文件系统读取数据、向控制台写入数据以及操作内存中的字符串都是很简单的事情。预计操作系统会允许拥有足够权限的用户进行这些操作。没有明确的上下文界限。
不幸的是,这也是大多数现代网络威胁(如网络钓鱼攻击、权限升级、供应链攻击等)背后的问题所在。如果攻击者能够说服有权限的用户运行不可信的代码,他们往往就能窃取其他资源的访问权限。沙盒环境的存在就是为了防止这种情况发生,但它们通常速度缓慢、操作繁琐,而且给开发人员造成负担。WebAssembly 想要解决这个问题,而且在很多方面都做到了。但从根本上说,WebAssembly 模块无法访问其托管环境未提供的任何内容。
到目前为止,我们所看到的 MVP 和工具在很大程度上都是关于如何使代码可移植的。现在,我们将学习如何使应用程序具有可移植性。事实证明,解决方案的根本在于能否满足人们的期望。这不仅是语言的问题,也是应用程序接口可用性、运行环境配置、安全限制等方面的问题。因此,就像李小龙的名言一样,我们的主机环境并不总能满足我们正在运行的代码的期望。我们仍然可以掌控一切。
网络组装系统接口(WASI)
到目前为止,您在上看到的超酷演示和代码示例,尤其是涉及图形、声音、视频等方面的演示和示例,之所以能够在浏览器中运行,很大程度上是因为它们是在浏览器中运行的。浏览器是一个通用客户端软件,是其他代码的宿主。可以通过向客户端发送任意程序来扩展网络。它有内置的安全限制,但实际上是一个功能丰富的编程环境,其中充满了各种应用程序接口,如用于 3D 图形的 WebGL、加速视频、用于协作的 WebRTC 等等。Emscripten 可通过浏览器运行时环境提供 POSIX 和 OpenGL 等标准 API 的实现,因此标准 C/C++ 应用程序只需编译即可运行。
我们已经看到了一种为模块实例提供函数的机制,模块实例可以通过它们导入的对象来调用这些函数。例如,还记得在 JavaScript 中传递一个可以打印到控制台的函数,而不是依赖 C 标准库来提供对printf() 的访问。不过,这种方法从根本上来说并不令人满意。每个需要打印到控制台的 WebAssembly 模块都应该有一个可以调用的函数,最好是已经编写好的函数。这样才能安全、高效地达到预期目标。
不过,出于安全考虑,李小龙名言的另一部分也很重要。程序想要读取或写入文件系统,并不意味着它就能读取或写入文件系统。我们的关键业务台式电脑并不是为了满足恶意软件的期望而存在的。我们希望控制应用程序访问资源的上下文(如果有的话)。
另一个与期望值有关的问题是,浏览器之外的运行时环境是 WebAssembly 潜在执行面的重要组成部分。在 Node.js 或 Deno 等环境中,许多 API 都无法以同样的方式使用。在访问音频和视频播放、3D 图形等方面,没有兼容的 Web IDL 定义接口。1当然还有其他类似的 API,但它们与浏览器内部的 API 并不直接兼容,因此必须重写应用程序才能使用它们。
通常情况下,POSIX 函数将在不同的操作系统中得到一致的定义,并映射到较低级别的内核函数或平台特定的应用程序接口 ...