哪些Java类/包在安全沙箱中是可以放行的?

9
作为我正在开发的Java游戏的一部分,我计划嵌入Groovy(或其他可能的)脚本语言,以允许更低级别的mod支持,并提供一种方式,使诸如对话和任务文件能够在游戏世界中产生效果。然而,我的目的和潜在的mod作者的目的可能会有所不同,如果可能的话,我想避免削减那些并不危险的语言功能。
虽然我的具体需求当然与公共规范有所不同,但我仍然很好奇是否有任何普遍认可的白名单(无论多短),可以访问Java包和类,而不会对用户造成重大风险。

1
这段代码是在服务器上运行还是在客户端机器上运行? - Andrew Thompson
1
虽然不完全相同,但如果您尚未发现它,这个问题可能对您也有用:https://dev59.com/02025IYBdhLWcg3wHR8Y - Trevor Freeman
@AndrewThompson 代码将在客户机上运行,但问题是我最终想添加多人支持和托管修改过的服务器的功能。在这种情况下,我正在研究允许这些(第三方)修改过的服务器直接向连接的客户端提供必需的修改文件(可能包含脚本)的可行性。当然,这需要成为“选择加入”的过程,但这并不会减少安全问题。请参见此处 - Hawkwing
"..以及托管修改后的服务器的能力。" 然后,您甚至需要考虑像 while(true); 这样简单的事情 - 它会消耗大量的 CPU 周期。 - Andrew Thompson
@AndrewThompson 这更像是一个需要担心的问题,如果我托管的服务器正在执行用户提交的代码的话。目前发生的情况是,运行我的游戏的客户端将执行由我无法控制的服务器提供的代码。我不认为仅仅导致减速的模组会构成安全风险,因为用户可以简单地结束程序,在下次启动时移除该模组,并继续进行。 - Hawkwing
3个回答

4
我仍然很好奇是否有任何普遍认可的Java包和类的白名单(即使很短),可以在不对用户造成重大风险的情况下访问。是的,有白名单,但我不知道它们有多么“普遍认可”。社区共识是审核白名单的一种方式,但您还可以查看列表创建者的经验,并查看他们的过程是否合理。
Joe-E项目提出了对Java进行“驯服”的想法,其中的一个部分是通过类/方法/字段的白名单来限制核心库的使用。例如,对于StringBuilderStringBuilder.safej表示:
# Manually verified.
class("java.lang.StringBuilder",
  static(constructor("StringBuilder()"),
    constructor("StringBuilder(CharSequence)"),
...
    method(suppress, "insert(int, Object)", comment("calls toString on arbitrary object")),

Runtime.safej 说:

# auto-generated safej: default deny everything
class("java.lang.Runtime",
  static(method(suppress, "getRuntime()", comment("default deny")),
    method(suppress, "runFinalizersOnExit(boolean)", comment("default deny"))),
    ...

要了解驯服(taming),请参见Joe-E 论文,其中写道:

4.2.1 驯服Java类库

Java类库定义了许多具有外部影响的静态方法,以及许多构造函数,这些构造函数创建允许类似效果的对象。这是Java中环境权限的主要来源。例如,File具有一个构造函数,它将接受一个字符串并返回表示该名称文件的对象。生成的对象可用于读取、写入或删除命名文件。在Java安全管理器或操作系统没有明确访问控制的情况下,这允许任何Java代码完全控制文件系统。在Joe-E中,我们希望确保只有在代码的动态范围内存在文件(或超级目录)的能力时,代码才能访问该文件。

因此,在Joe-E的全局范围内,我们不允许使用上述的File构造函数。 我们定义了Java库的子集,其中仅包括与所有特权必须通过能力授予相容的构造函数、方法和字段。我们称这个活动为驯服,因为它将一个难以管理的类库转化为一个能力安全的子集。 JoeE验证器允许Joe-E程序仅提及此被驯服的子集中的类、构造函数、方法和字段。如果源代码提到了此子集之外的任何内容,则Joe-E验证器将其标记为错误。

驯服有助于消除环境权限,因为它确保提供环境权限的库方法不可用于Joe-E程序。我们还使用驯服来仅暴露Java库的那个提供能力纪律的子集。


1
如果字节码静态分析可以白名单API的一些位,那将是很有趣的。不过这很棘手。/ File 是一个有趣的类。它应该代表一个文件路径字符串。危险在于所有具有安全检查的方法。(另一个大危险在于 File 实际上并不是不可变的。 - Tom Hawtin - tackline
@TomHawtin-tackline,一些静态流分析可以帮助调试白名单,通过暴露缺失的源来处理new java.io.FileInputStream(String, String)作为汇聚点,并确保到达它的所有字符串都被白名单识别为系统资源。由于存在java.lang.reflect.Method和制作不透明谓词的容易性,它永远不会完整,可能不会接近保守。 - Mike Samuel
1
Java反射不会被列入白名单。我记不清Joe-E是否支持此功能,但某些对象能力语言通过邀请支持反射(代码可以创建一个具有反射访问权限的对象,就像创建它的代码一样 - 然后可以将其传递给更通用的代码)。同样,任何使用反射的代码都将难以列入白名单。即使是使用可变静态变量的代码(例如private static final char[])也将极为棘手。 - Tom Hawtin - tackline
@TomHawtin-tackline,我认为你是对的。如果我没记错,Joe-E提供了一种减弱的替代方案而不是驯服。Mark Miller喜欢动态类型系统有很多原因,其中一个原因是当一个对象只是一个记录时,作者倾向于不会通过错误地假设仅可用静态类型的操作符来泄露权限。 - Mike Samuel

1
我猜你会发现,与其从一个通用的编程语言开始,然后想办法让人们能够访问它并使其安全,不如反过来更加安全。我的方法是从一个特定领域的语言开始,并给它访问沙盒的权限——那些你愿意和乐意让修改者影响的程序环境方面。

1
唉,我既没有时间开发自己的领域特定语言,也没有影响力让人们为了在我的游戏中进行修改而学习它。不幸的是,在这种情况下,我必须尽最大努力保障安全性,以便让模组制作者更容易地采用该语言,并且让我能够在没有无限预算和时间的情况下开发软件。 - Hawkwing
@Hawkwing 好的,祝你好运。 - CPerkins
Mike Samuel的回答提到了Joe-E,它是Java的安全子集。这似乎是一个更好的方法。然而,困难在于库。 - Tom Hawtin - tackline

0

我会尝试模拟Java小程序沙盒模型。如果这个沙盒足够安全,可以在我的电脑上运行来自互联网的任意代码,那么它应该也足够安全来运行你的用户脚本。不过,你可能不希望用户脚本弹出一些GUI窗口,所以你需要比小程序沙盒更加限制权限。


用户脚本通常由初学者开发,并且接受的审查比调用它们的应用程序少,因此更容易出现“混淆代理”漏洞,如脚本注入,而不是核心代码库。 - Mike Samuel
OP希望支持用户脚本并想知道如何安全地实现。 - ZhongYu
同意。原帖作者明智地尝试授予用户脚本足够的权限来完成其工作,但不要过多,因为脚本作者的天真和较低的审查和测试标准。 - Mike Samuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接