0

我正在开发一个 Java 项目。在其中,我们希望最终用户能够定义基于一组给定的原始类型或字符串变量计算的变量。在某些时候,所有给定的变量都设置为特定的值,然后应该进行计算。然后必须将所有生成的计算变量发送到 Java。

我正在评估最终用户定义其计算的方法。(当前)想法是让他编写 JavaScript 并让该代码在 Java 程序中解释/执行。我知道有两种方法可以做到这一点:使用 javax.scripting API 或 GraalVM/Truffle。在这两种情况下,我们都会这样做:

  1. 给定的变量被赋予到脚本中。在 javax.scripting 中ScriptEngine.put,在 Graal/Truffle 中,通过Value.putMember.
  2. 最终用户可以在全局上下文中定义变量(其名称不得与来自 Java 的名称冲突)。他如何设置它们的值取决于他 - 他可以直接设置它们(到一个常数,到给定变量之一,到其中一些的总和......)或定义对象和函数并通过调用这些来设置值.
  3. 当给定变量具有固定值时,将执行脚本。
  4. 脚本在全局上下文中定义的所有变量都将发送到 Java。在 javax.scripting 中ScriptEngine.get,在 Graal/Truffle 中,通过Value.getMember.

注意:我们不会授予脚本访问任何 Java 类或方法的权限。在 javax.scripting 中通过检查脚本是否包含字符串Java.type(并禁止这样的脚本),在 Graal/Truffle 中通过使用默认值Context(具有allowAllAccess=false)。

互联网上充满了关于 JavaScript 安全问题以及如何避免它们的提示和技巧。一方面,我觉得它们都不适用于这里(解释如下)。另一方面,我不太了解 JavaScript——除了纯粹的、无副作用的计算,我从未将它用于其他任何事情。

所以我在这里寻找一些指导:在这种情况下可能会出现什么样的安全问题?


为什么在这种情况下我看不到任何安全问题:

这是纯 JavaScript。它甚至不允许创建可用于例如在磁盘上创建文件的 Blob(它是 WebAPI 的一部分,而不是 JavaScript)。我知道 JavaScript 不包含任何逃避其沙箱的功能(如文件访问、线程、流......),它仅能够操纵提供给其沙箱的数据。请参阅https://262.ecma-international.org/11.0/#sec-overview的这一部分:

ECMAScript 是一种面向对象的编程语言,用于在主机环境中执行计算和操作计算对象。此处定义的 ECMAScript 并非旨在实现计算自给自足;实际上,本规范中没有规定外部数据的输入或计算结果的输出。相反,预计 ECMAScript 程序的计算环境将不仅提供本规范中描述的对象和其他设施,还提供某些特定于环境的对象,其描述和行为超出了本规范的范围,除非指出它们可以提供可以访问的某些属性和可以从 ECMAScript 程序调用的某些函数。

我们场景中的沙箱只放入了一些无害的玩具(即给定的原始类型或字符串的变量),在孩子玩过它们(脚本已运行)后,生成的建筑物(用户定义的变量)被拿走出来保存它们(在Java程序中使用)。

4

2 回答 2

4

(1) 在虚拟机中运行的代码可能会逃逸。即使对于众所周知的 JS 实现,例如 V8,这种情况也经常发生。通过在您的服务器上运行不受信任的代码,只要已知此类漏洞,您就很容易受到攻击。您绝对应该为此做好准备,进行风险评估,例如,在引擎运行的(虚拟)机器上可以访问哪些其他数据(其他客户数据?,秘密?),并额外加强您的基础设施以防止这种情况。

(2) 它停止了吗?如果客户跑了while(true);怎么办?这会使您的服务器崩溃吗?可以通过在某个超时后终止执行来防御这种情况(不要尝试验证代码,这永远不会可靠地工作)。

(3) 使用的资源是否有限(内存)?用a = ""; while(true) a += "memory";一个可以轻松分配大量内存,对其他程序产生负面影响。还应确保内存使用受到限制,以使程序在资源耗尽之前被终止。

于 2021-08-12T13:22:27.293 回答
2

只是一些想法。您本质上是在询问您是否可以信任您的沙盒/虚拟机,因为您应该假设您使用的是一个好的,或者唯一确定的方法是自己阅读它的所有源代码。如果您选择一个受信任且众所周知的沙箱,我猜您可以信任它(javascript 不应该能够影响它之外的文件系统内容)。

另一方面,您为什么不只是在客户端进行所有这些计算,然后将结果发送到您的后端,似乎很多设置只是为了能够运行 JavaScript 服务器端。如果对此的论点是“不作弊”或类似的东西,那么即使您的代码已发送到服务器(您不知道是谁向您发送了该 javascript),您也无法避免这种情况。在我看来,做这个设置只是为了在服务器端运行它是没有意义的,只是在客户端运行它。

如果您确实需要在服务器端使用它,那么您需要考虑您的 java 是否以 root 权限运行(在这种情况下,它可能还会以 root 权限调用沙箱)。在我的设置中,我的 nodejs 在 ~/home 下执行,所以即使发生最坏的情况并且有人设法删除了所有他们能做的最坏的事情,就是清除主目录。如果您正在运行 javascript 服务器端,那么我强烈建议您至少不要在 root 下这样做。它不应该在那个沙箱之外做任何事情,但至少即使在最坏的情况下它也不能消灭你的服务器。

我要考虑的其他事情(因为我不知道您的沙箱允许或限制什么)是您是否可以在该沙箱(或类似的东西)中请求和使用 javascript 进行 API 调用,因为如果它在 root 下运行并允许它会授予某人对您的基础架构的 root 访问权限(您的基础架构认为它是您的服务器发出请求,而实际上它是恶意 JS 代码)。

您也可能会犯错误或使用不正确的参数或缺少配置选项启动虚拟机,并且它会突然出现漏洞,而您没有意识到这一点,因此您必须确保正确设置它。

另一件事是,如果您曾经将该 JS 存储在某个数据库中,而不仅仅是执行它,那么您必须确保它不会直接提供给任何其他用户而不检查它,否则您会发生 XSS。例如,您为“编码测试”构建了一个应用程序并将其测试结果存储在数据库中,然后您想将该结果显示给潜在雇主,如果您直接向他们显示该结果,您将执行恶意代码他们的浏览器。

但我真的不明白为什么你应该关心这些,只是在客户端运行它。

于 2021-08-12T13:15:23.403 回答