Cra*_*her 5 java groovy jvm sandbox
我正在创建一些将采用任意 Groovy 代码并执行它的东西(一个 IRC 机器人)。我知道如何使用 SecurityManagers 对文件访问、线程等进行沙盒处理,但是如果脚本的 RAM 使用量超过 128 MB 或执行时间超过 3 秒(因此没有人让它运行while (true){}),我想杀死脚本。这是我的代码:
private static Object eval(String code) {
GroovyShell sh = new GroovyShell()
return sh.parse(code).run()
}
Run Code Online (Sandbox Code Playgroud)
我真的不想生成一个新的 JVM,因为我希望将异常传递给主程序并传递实际对象而不是字符串(如果我打算制作其他前端,则可以重复使用)。
只需在单独的进程中运行每个脚本即可。
有几件事需要注意。第一种是将每个脚本放入其自己的类加载器中,该类加载器具有扩展类加载器,甚至可能是将引导类加载器作为其父级。这是为了控制 groovy 脚本对应用程序类的访问。
监控执行时间很容易。只需在其自己的线程中运行每个脚本,并在超过 3 秒限制时中断该线程。但请记住,中断线程只会引发 InterruptedException,可以在该线程中捕获并处理该异常。如果代码设计为从这些异常中恢复,那么停止线程并不容易。
记忆部分是事情真正崩溃的地方。这个答案几乎说明了需要说的一切——不可能。有人可以轻松耗尽堆空间并使 jvm 崩溃。
最终,我真的建议在单独的进程中运行每个进程。这样做有几个好处,其中最重要的是,通过以单独的用户身份运行它们,可以更轻松地对它们进行沙箱处理。这样您就可以从操作系统获得另一级别的保护。
另外,如果您想将异常传递回主 java 进程,这可以很容易地完成,因为 Exception 实现了Serialized。这意味着您可以轻松地将异常通过SocketChannel或通过 http、序列化到文件或使用您想要的任何协议发送回主进程。查看这篇文章,了解序列化的一些基本信息。