gpt4 book ai didi

java - 如何搭建沙箱环境

转载 作者:行者123 更新时间:2023-11-30 07:58:54 25 4
gpt4 key购买 nike

您好 SecurityManager 专家 ;-)

我编写了一个小型插件框架,它使用单独的隔离类加载器加载插件。要成功取消部署插件,重要的是要确保应用程序不保留对插件类加载器加载的类的引用。

Java 中有一个称为关闭 Hook 的功能,它使客户端代码能够注册一个线程,该线程在 JVM 被请求关闭时执行。这意味着 JVM 可能会持有对插件类加载器加载的类的引用。

我的第一次尝试是安装一个拒绝添加关闭 Hook 的 SecurityManager。这完全有效并拒绝所有添加关闭 Hook 的尝试。有趣的是,我意识到,想要添加关闭 Hook 的不是插件本身。该插件仅通过加载字体触发 AWT/Swing 内部结构(精确:SunFontManager)。 SunFontManager 依次添加关闭 Hook 以在 JVM 退出时执行一些内部处理。我不想否认插件加载字体(因为它必须加载),我不想否认 Java 内部添加他们的东西。

对我来说,我似乎必须授予代码更多权限(如果 sun.*|java.*|javax.* 包在堆栈跟踪中..uuuhmm.. .ugly) 比正常情况下。但这打破了安全框架的约定,该约定假定客户端代码不能拥有比调用它的代码更多的特权。

我如何区分不是插件代码而是 Java 内部想要做某事?或者是否有任何其他方法可以确保不会通过否认某些东西来破坏内部结构?

发生的事情的例子

为了让事情更清楚,这是我的应用程序中实际发生的事情。我安装了一个自定义的 SecurityManager,它应该拒绝插件直接执行的 addShutdownHook,但如果作为 Java 内部类的副作用执行,则不应拒绝这些调用。

Context:            Calls:----------------------------------------------AppClassloader      Application                        |PluginClassloader   PluginObject.init()                        |AppClassloader      Font.create()                        |                    AccessController.doPrivileged(...) {                        Runtime.addShutdownHook(...)                    }

The SecurityManager was installed using System.setSecurityManager() and does this:

@Override
public void checkPermission(java.security.Permission perm) {
if (perm.getName().equals("shutdownHooks")) {
if (threadContextClassLoaderIsPluginClassLoader()) {
throw new SecurityException("Installing shutdown hooks is not allowed.");
}
}
}

尽管 addShutdownHook 是在 doPrivileged block 中调用的,但我的 SecurityManager 被调用了。我错过了什么吗?我应该自己检查特权上下文吗?

最佳答案

我发现我完全误解了 Java 安全概念。我想为插件代码构建一个沙箱,以便它始终在受限环境中运行,我可以控制它拥有的权限。该应用程序应始终在授予完全访问权限的情况下运行。

以下是如何为由单独的类加载器加载的类构建沙箱:

  1. 使用默认的 SecurityManager 如果您发现自己实现了自己的 java.lang.SecurityManager根据您可能做错的权限允许或拒绝操作!你只需要安装默认的java.lang.SecurityManager通过这样做 System.setSecurityManager(new SecurityManager()); .现在,您可以使用 Java 默认值获得有效的访问控制。
  2. Grant all permissions to application 加载插件的应用程序应该获得完全访问权限。这是因为我们相信自己。我通过使用授予所有访问权限的策略文件启动我的应用程序来解决这个问题。我认为应用程序启动时需要策略文件,因为 AppClassLoader 需要为类创建正确的保护域。使用 JavaVM 参数启动主应用程序 java.security.policy=<URL-TO-POLICY>其中 <URL-TO-POLICY指向以下策略文件:

    grant {
    permission java.security.AllPermission;
    };

  3. 自定义策略实现 我们需要在应用程序启动后安装我们的自定义策略。我们想要分离主应用程序(在授予完全访问权限的情况下运行)和插件(我们想要限制的权限)的权限。插件应在具有精选权限的沙箱中运行。为实现这一点,这里是自定义策略实现:

    class SandboxPolicy extends Policy {
    @Override

    public PermissionCollection getPermissions(ProtectionDomain domain) {
    // Decide if the plugin permissions are needed or full access can be granted using all permissions.
    if (isPlugin(domain)) {
    return pluginPermissions();
    } else {
    return applicationPermissions();
    }
    }

    private boolean isPlugin(ProtectionDomain domain) {
    // Identify the classloader of the protection domain
    // The PluginClassLoader is assumed to be the one that loaded
    // the plugin
    return domain.getClassLoader() instanceof PluginClassLoader;
    }

    private PermissionCollection pluginPermissions() {
    // Empty permissions = No permissions
    // This is not the point to add plugin permissions
    return new Permissions();
    }

    private PermissionCollection applicationPermissions() {
    // Grant full access to the application
    Permissions permissions = new Permissions();
    permissions.add(new AllPermission());
    return permissions;
    }
    }
  4. 每个类加载器的 ProtectionDomains 类加载器负责创建一个 ProtectionDomain对于每个来源,代码都是从中加载的。保护域指定将授予代码的权限。我们必须修改类加载器添加到保护域的权限集。为此,让您的 PluginClassloader 扩展 java.security.SecureClassLoader .然后覆盖方法 java.security.SecureClassLoader.getPermissions(CodeSource)通过以下方式:

    @Override
    protected PermissionCollection getPermissions(CodeSource codeSource)
    {
    PermissionCollection pc;
    // The SecureClassloader per default grants access to read resources from the source JAR.
    // This is useful. Call super to get those permissions:
    pc = super.getPermissions(codeSource);
    // At this point you can extend permissions.
    // For example grant read access to a file.
    pc.add(new FilePermission("path\\file", "read"));
    return (pc);
    }

注意:看政策执行,看看我的评论// This is not the point to add plugin permissions . AccessController 询问政策查看是否可以授予权限。如果在此处添加权限,您可以从调用者那里获得的信息非常有限。我不建议在此处计算和添加任何权限。类加载器是您可以根据代码源添加权限的地方。我建议在这里添加权限。它们在保护域中变得可见,您可以轻松观察 AccessController 使用这些保护域执行的操作。

特权操作

我想回答问题中的另一部分。

The interesting thing is, that I realized, that it is not the plugin itself that wants to add a shutdown hook. The plugin just triggers the AWT/Swing internals (precise: SunFontManager) by loading a font.

有些操作将作为插件代码的副作用执行。 A类org.plugin.A可以触发 Swing/AWT 内部添加一个关闭钩子(Hook)。在这种情况下,我们不想否认这一点。 Java 类在应用程序的范围内,应该具有完全访问权限。插件代码可能会受到限制,直接添加关闭 Hook 应该会失败并返回 SecurityException。 .这是 java.security.AccessController.doPrivileged(PrivilegedAction<T>) 的常见用例.特权操作确保 AccessController只会考虑最后一个堆栈帧的保护域。 AWT/Swing 将其关闭 Hook 添加到一个特权操作中,因此被允许这样做,因为在该操作中执行的类的保护域设置为具有完全访问权限。请参阅 java.security.AccessController 的任何文档了解有关特权操作的更多信息。

关于java - 如何搭建沙箱环境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39974300/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com