Groovy Shell 沙盒最佳实践

Groovy Shell Sandboxing Best Practices

我正在尝试设置一个可以执行不受信任代码的 Groovy Shell 沙箱。这些不受信任的代码由最终用户(开发人员)作为行为配置提供,例如如何判断一个人是不是高净值。所以,它们确实是主程序的一部分。我需要确保我不会受到任何错误代码的攻击[例如无限循环]/hacks.

我知道这里有两件事在起作用:

  1. 提供运行时的Java VM。
  2. 解释执行代码的GroovyShell

是否有沙盒 Groovy Shell 的最佳实践?

谢谢

多一点上下文会有所帮助,但考虑到您的描述:

我强烈建议 运行在一个容器中安装 groovyshell - 每个 user/instance 一个容器。

您可以严格控制磁盘访问,还可以为 CPU 和容器的内存使用设置上限。

如果您想走极端,您可以轻松地运行网络中的每个容器,没有其他节点,也没有互联网访问权限。

如此一来,不良代码将完全限于 docker 个可以从 JVM 程序中利用的漏洞。

我最终创建了一个策略文件。像这样:

grant codeBase "file:/your jar file" {
  permission java.security.AllPermissions;
}

grant codeBase "file:/groovy/shell" {
}

grant codeBase "file:/groovy/script" {
}

当Groovy在解释模式下执行时,codeBase是file:/groovy/shellfile:/groovy/script。您可以为任一上下文授予特定权限。这些权限(或缺少权限)与您为主程序提供的权限无关。

除了策略文件,还有很多其他的注意事项。

  1. 您将什么放入评估上下文中?如果您放置第三方库,他们甚至可能没有适当的权限检查。

  2. 一些系统调用,比如System.out.println()也没有权限检查。所以,也许你还需要一个源代码检查器(Jenkins 做的)。

  3. 要限制 CPU,您可能需要 运行 单独线程中的 Groovy 脚本。

  4. 您可能想限制 Groovy 脚本也可以 import 的内容。这可以通过 Groovy ImportCustomizer.

    来实现

我写了一篇文章:Secure Groovy Script Execution in a Sandbox 来总结我的发现。希望对其他人也有帮助。

仅靠安全管理器并不能解决所有问题。安全管理器不适合的原因有多种。最重要的是,它依赖于关键方法已经包含适当权限检查的假设。正如已经指出的那样,情况并非总是如此。仅在 Java SE API 中,就有很多例子;将范围扩展到更多的 3rd 方库,您将很少看到执行权限检查的良好实现。这不能改装。安全管理器是为保护桌面系统而设计的;相反,在 multi-user 系统上,您需要额外的保护以防止对其他用户的攻击。

一种可行的方法是 Jenkins 所做的:拦截所有方法调用和成员访问并检查配置的白名单。这是在 https://github.com/jenkinsci/script-security-plugin

中实现的

这里很关键的一点是如何维护一个可用的白名单。 Jenkins 方法适用于广泛的方法签名列表(加上黑名单)。虽然这是一种保守的方法,但维护起来可能很乏味。您应该从您想要提供的尽可能小的 API 子集开始。充其量,有一个专门的 API 供脚本用户隐藏所有实现细节。

仍然存在一些极端情况,特别是在资源耗尽方面。例如考虑以下脚本:

for( int x = 7; true; x *= x );

这个无限循环将使 CPU 保持忙碌,同时没有要拦截的方法调用或字段分配。恕我直言,处理此问题的最佳方法是在单独的线程中执行脚本并在给定的超时后停止它。是的,我的意思是调用 Thread.stop(),因为中断将被忽略。最后,脚本可以引发任何 Throwable,甚至可以在不声明它们的情况下检查它们;您应该始终在脚本周围使用 catch Throwable