如何禁止用户在 Groovy 脚本中做坏事?

问题描述 投票:0回答:4

我计划将 Groovy 脚本引擎集成到我的游戏中,这样它将为游戏提供良好的可修改性,但是如何防止玩家编写邪恶的脚本,例如删除 C: 驱动器上的所有文件?

Groovy 默认包含像

java.io.File
这样的库,因此一旦他们决定编写此类脚本,这将非常容易做到。

我想我无法阻止用户编写类似

while(1==1){}
之类的内容,但至少有没有办法让他们允许删除/修改文件或对电脑造成危险的东西?

security groovy
4个回答
2
投票

Cedric Champeau 有一篇关于自定义 Groovy 编译过程的 博客文章,它的第二部分展示了如何使用

SecureASTCustomizer
CompilerConfiguration
来限制脚本可以执行的操作(然后有定义您自己的 AST 检查的示例)对于
System.exit
等...


2
投票

我知道这是一个老问题。我发布此内容是因为它可能会帮助一些人。

我们需要允许最终用户上传 Groovy 脚本并将其作为 Web 应用程序的一部分执行(该应用程序可以执行许多其他操作)。我们担心的是,在这些 Groovy 脚本中,某些用户可能会尝试从文件系统读取文件、读取系统属性、调用 System.exit() 等。

我查看了 http://mrhaki.blogspot.com/2014/04/groovy-goodness-restricting-script.html 但这并不能阻止专家 Groovy 开发人员绕过其他帖子中其他人指出的检查.

然后我尝试让 http://www.sdidit.nl/2012/12/groovy-dsl-executing-scripts-in-sandbox.html 工作,但在运行时设置安全管理器和策略实现不起作用我。我在应用程序服务器启动和网页访问期间不断遇到问题。似乎当策略实现生效时,为时已晚,“CodeSources”(Java 安全术语)已经从默认的 Java 策略文件中获取了访问设置。

然后,我偶然发现了 Ted Neward 撰写的出色白皮书(http://www.tedneward.com/files/Papers/JavaPolicy/JavaPolicy.pdf),该白皮书非常令人信服地解释了(对于我的用例而言)最好的方法是在 JVM 启动时设置策略实现(而不是稍后动态设置)。

下面是对我有用的方法(结合了 Rene 和 Ted 的方法)。顺便说一句:我们正在使用 Groovy 2.3.10。

在 [JDK_HOME]/jre/lib/security/java.security 文件中,将“policy.provider”值设置为“com.yourcompany.security.MySecurityPolicy”。

创建 MySecurityPolicy 类:

import java.net.MalformedURLException;
import java.net.URL;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.util.HashSet;
import java.util.Set;

public class MySecurityPolicy extends Policy {
    private final Set<URL> locations;

    public MySecurityPolicy() {
        try {
            locations = new HashSet<URL>();
            locations.add(new URL("file", "", "/groovy/shell"));
            locations.add(new URL("file", "", "/groovy/script"));
        } catch (MalformedURLException e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public PermissionCollection getPermissions(CodeSource codeSource) {
        // Do not store these in static or instance variables. It won't work. Also... they're cached by security infrastructure ... so this is okay.
        PermissionCollection perms = new Permissions();
        if (!locations.contains(codeSource.getLocation())) {
            perms.add(new AllPermission());
        }
        return perms;
    }
}

将 MySecurityPolicy 打包并放入 [JDK_HOME]/jre/lib/ext 目录中。

将“-Djava.security.manager”添加到JVM启动选项中。您不需要提供自定义安全管理器。默认的就可以了。

“-Djava.security.manager”选项为整个应用程序启用 Java 安全管理器。应用程序及其所有依赖项将具有“AllPermission”,因此将被允许执行任何操作。

Groovy 脚本在“/groovy/shell”和“/groovy/script”“CodeSources”下运行。它们不一定是文件系统上的物理目录。上面的代码没有给 Groovy 脚本任何权限。

用户仍然可以执行以下操作:

  • Thread.currentThread().interrupt();

  • while (true) {}(无限循环)

您可以将以下内容(在运行时动态地)添加到每个脚本的开头,然后将其传递到 Groovy shell 执行:

@ThreadInterrupt
import groovy.transform.ThreadInterrupt

@TimedInterrupt(5)
import groovy.transform.TimedInterrupt

这些内容在 http://www.jroller.com/melix/entry/upcoming_groovy_goodness_automatic_thread

进行了解释

第一个处理“Thread.currentThread().interrupt()”更优雅一些(但它不会阻止用户中断线程)。也许,你可以使用 AST 来在某种程度上防止中断。在我们的例子中,这不是一个大问题,因为每个 Groovy 脚本执行都在自己的线程中运行,如果坏人希望杀死自己的线程,他们可能会把自己击倒。

第二个可以防止无限循环,因为所有脚本都会在 5 秒后超时。您可以调整时间。

请注意,我注意到 Groovy 脚本执行时间的性能下降,但没有注意到 Web 应用程序其余部分的性能显着下降。

希望有帮助。


1
投票

查看 SecurityContext 类。


1
投票

Groovy Web Console 似乎已经解决了这个问题,因为它不会执行类似

System.exit(1)
的操作。 源代码可在 GitHub 上找到,因此您可以了解他们是如何做到的。

如果您不确定从哪里开始,我建议与作者联系,他应该能够为您指明正确的方向。

© www.soinside.com 2019 - 2024. All rights reserved.