- 适用于 JDK 23 的 GraalVM(最新版)
- 适用于 JDK 24 的 GraalVM(抢先体验版)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发版本
安全指南
本安全指南为开发者和嵌入者提供了有关 GraalVM 安全模型和功能的信息,这些信息可以帮助他们构建基于 GraalVM 的安全应用程序。本指南假定读者熟悉 GraalVM 架构。本指南不会取代而是补充 Java 安全文档,例如Java SE 安全编码指南,其中包含 GraalVM 的独特方面。
安全模型 #
GraalVM 是一个共享运行时。它接受高级编程语言(或其中间表示)的指令作为输入,并在稍后执行这些指令。在 GraalVM 上运行代码中实现应用程序安全控制(例如访问控制)的开发者可以依赖指令的正确执行。在 GraalVM 上运行的安全关键代码执行错误,导致绕过此类安全控制,被视为安全漏洞。
调试功能应仅在受信任的环境中使用,因为它们提供对应用程序的特权访问,允许检查和更改其状态和行为。它们还可以打开网络套接字,以允许调试客户端连接。
GraalVM 中的实验性功能不适用于生产环境,并且可能存在安全指南中未涵盖的安全限制。
GraalVM 允许在适当配置的多语言执行上下文中执行不受信任的代码(请参阅沙箱)。
我们感谢您通过漏洞报告指南中概述的过程报告破坏安全模型的错误。
Graal 语言 #
每个语言运行时(通常随 GraalVM 版本提供)都提供一个启动器,例如一个交互式 shell。这些启动器具有相同的行为,并提供与其“原始”对应版本相同的安全保证。
沙箱 #
沙箱可以通过多语言 API在特权主机代码和非特权来宾代码之间建立安全边界。有关更多信息,请参阅沙箱文档。
脚本引擎兼容性 #
出于向后兼容性的原因,某些多语言语言还支持Java 脚本 API。例如,这允许 GraalVM Javascript 运行时作为 Nashorn 的直接替代。但是,为了保持兼容性,Nashorn GraalVM JavaScript 脚本引擎接口将创建一个上下文,其中所有特权都授予脚本,因此应谨慎使用,仅用于受信任的代码。
托管的本机代码执行 #
多语言嵌入还支持 LLVM 中间表示(IR)来宾代码。几种本机系统编程语言(尤其是 C/C++)可以使用 LLVM 编译器工具链编译为 LLVM IR。通常,这些语言并非内存安全的,除非使用托管执行,并且必须记住,违反内存安全是安全漏洞的常见原因。
在托管模式下,所有对非托管代码(包括操作系统)的访问都由语言运行时进行仲裁。特别是,这意味着
- 在时间和空间内存安全方面,内存是从 Java 堆分配的。这意味着内存分配是托管对象,所有访问都以内存安全的方式执行(没有任意指针运算,也没有未经检查的越界访问)。
- 关于类型安全,无法将数据指针重新解释为函数指针并执行任意指令(因为这些是 LLVM 运行时的不同指针类型)。
- 系统调用被拦截并路由到相应的 Truffle API。例如,文件 I/O 被映射到 Truffle 的
FileSystem
API。当前支持的系统调用集非常有限——只有可以安全地映射到 Truffle API 级别上的系统调用可用。由于 LLVM 运行时在托管模式下始终运行针对 Linux/x86 编译的位代码,因此它只需要为该平台实现系统调用。 - 所有依赖库也在托管模式下执行,消除了对本机执行的系统库的所有引用。这包括 LLVM 运行时提供的库,例如 muslibc。
在创建上下文(Context.create())
或通过指定--llvm.managed
选项调用bin/lli
二进制文件时,可以选择托管模式。一个“托管”上下文将遵守在上下文创建期间传递的任何限制(例如,allowIO
),并且不需要allowNativeAccess
特权。
Native Image #
使用 GraalVM Native Image,应用程序的状态在启动后被捕获,所有可到达的代码都被提前编译,并打包为本机可执行文件。有关更多信息,请参阅Native Image 安全指南。
安全管理器 #
安全管理器已在JEP-411中弃用。GraalVM 不支持在 Java 中执行不受信任的代码。
GraalVM 社区版降级 #
GraalVM 社区版中不提供沙箱功能。使用 GraalVM 社区版时,无法使用本机代码的托管执行。
降级到 GraalVM 社区版时,仅当使用allowNativeAccess
特权时,才能执行本机代码。这同样适用于使用 Truffle 实现的语言,这些语言允许进行本机代码扩展,例如 Python 和 Ruby。