安全指南

本安全指南为希望在其上构建安全应用程序的开发人员和嵌入者提供了有关 GraalVM 安全模型和功能的信息。它假定读者熟悉 GraalVM 架构。本指南不取代,而是补充了 Java 安全文档(例如 Java SE 安全编码指南)中 GraalVM 独有的方面。

安全模型 #

GraalVM 是一个共享运行时。它接受高级编程语言(或其中间表示)的指令作为输入,并随后执行这些指令。在 GraalVM 运行的代码中实现应用程序安全控制(例如访问控制)的开发人员可以依赖指令的正确执行。在 GraalVM 上运行的安全关键代码执行不正确,导致绕过此类安全控制,则被视为安全漏洞。

调试功能应仅在受信任的环境中使用,因为它们提供对应用程序的特权访问,允许检查和更改其状态和行为。它们还可能打开网络套接字以允许调试客户端连接。

GraalVM 中的实验性功能不适用于生产环境,并且可能存在本安全指南未涵盖的安全限制。

GraalVM 允许在正确配置的多语言执行上下文(参见沙盒)中执行不受信任的代码。

我们感谢通过漏洞报告指南中概述的流程报告破坏安全模型的错误。

Graal 语言 #

每个通常随 GraalVM 版本提供的语言运行时都提供一个启动器,例如交互式 shell。这些启动器的行为方式与其“原始”对应方相同,并具有相同的安全保证。

沙盒 #

沙盒可以通过 Polyglot API 在特权宿主代码和非特权访客代码之间建立安全边界。欲了解更多信息,请参阅沙盒文档

ScriptEngine 兼容性 #

出于向后兼容性考虑,某些 Polyglot 语言也支持 Java 脚本 API。例如,这允许将 GraalVM Javascript 运行时用作 Nashorn 的直接替代品。但是,为了保持兼容性,Nashorn GraalVM JavaScript ScriptEngine 接口将创建一个授予脚本所有权限的上下文,应极其谨慎使用,且仅用于受信任的代码。

本机代码的托管执行 #

多语言嵌入还支持 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 权限。

本机映像 #

使用 GraalVM 本机映像,应用程序的状态在启动后被捕获,并且所有可达代码都提前编译,以捆绑为本机可执行文件。欲了解更多信息,请参阅本机映像安全指南

安全管理器 #

安全管理器已在 JEP-411 中弃用。GraalVM 不支持 Java 中的非受信任代码执行。

GraalVM 社区版降级 #

沙盒功能在 GraalVM 社区版中不可用。本机代码的托管执行在 GraalVM 社区版中不可用。

降级到 GraalVM 社区版时,本机代码执行仅在拥有 allowNativeAccess 权限的情况下才可能。这也适用于用 Truffle 实现并允许本机代码扩展的语言,例如 Python 和 Ruby。

联系我们