Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java安全性:通过URLClassLoader加载沙盒插件 问题摘要:如何修改下面的代码,使不受信任、动态加载的代码在安全沙箱中运行,而应用程序的其余部分保持不受限制?为什么URLClassLoader不能像它说的那样处理它呢?_Java_Classloader_Securitymanager_Urlclassloader - Fatal编程技术网

Java安全性:通过URLClassLoader加载沙盒插件 问题摘要:如何修改下面的代码,使不受信任、动态加载的代码在安全沙箱中运行,而应用程序的其余部分保持不受限制?为什么URLClassLoader不能像它说的那样处理它呢?

Java安全性:通过URLClassLoader加载沙盒插件 问题摘要:如何修改下面的代码,使不受信任、动态加载的代码在安全沙箱中运行,而应用程序的其余部分保持不受限制?为什么URLClassLoader不能像它说的那样处理它呢?,java,classloader,securitymanager,urlclassloader,Java,Classloader,Securitymanager,Urlclassloader,编辑:更新以响应Ani B。 编辑2:添加了更新的插件安全管理器。 我的应用程序有一个插件机制,第三方可以提供一个JAR,其中包含一个实现特定接口的类。使用URLClassLoader,我能够加载该类并实例化它,没有问题。因为代码可能不可信,所以我需要防止它出现错误行为。例如,我在一个单独的线程中运行插件代码,以便在它进入无限循环或花费太长时间时可以终止它。但是,试图为他们设置一个安全沙箱,使他们无法进行网络连接或访问硬盘上的文件,这让我非常恼火。我的努力总是导致要么对插件没有影响(它具有与应用

编辑:更新以响应Ani B。

编辑2:添加了更新的插件安全管理器。

我的应用程序有一个插件机制,第三方可以提供一个JAR,其中包含一个实现特定接口的类。使用URLClassLoader,我能够加载该类并实例化它,没有问题。因为代码可能不可信,所以我需要防止它出现错误行为。例如,我在一个单独的线程中运行插件代码,以便在它进入无限循环或花费太长时间时可以终止它。但是,试图为他们设置一个安全沙箱,使他们无法进行网络连接或访问硬盘上的文件,这让我非常恼火。我的努力总是导致要么对插件没有影响(它具有与应用程序相同的权限),要么限制应用程序。我希望主应用程序代码能够做它想做的任何事情,但是插件代码要被锁定

关于这个主题的文档和在线资源是复杂、混乱和矛盾的。我在不同的地方(例如)读到我需要提供一个定制的SecurityManager,但是当我尝试它时,我遇到了问题,因为JVM延迟加载JAR中的类。所以我可以很好地实例化它,但是如果我在加载的对象上调用一个方法来实例化来自同一个JAR的另一个类,它就会崩溃,因为它被拒绝了从JAR读取的权利

理论上,我可以在SecurityManager中检查FilePermission,看看它是否试图从自己的JAR中加载。这很好,但是说:“默认情况下,加载的类只被授予访问创建URLClassLoader时指定的URL的权限。”那么,为什么我甚至需要自定义SecurityManager呢?URLClassLoader不应该处理这个问题吗?为什么不呢

下面是一个简单的例子,再现了这个问题:

主应用程序(受信任) pluginest.java PluginSecurityManager.java PluginThread.java 插件JAR(不可信) MyPlugin.java
更新: 我更改了它,以便在插件代码即将运行之前,它通知PluginSecurityManager,以便它知道使用的是什么类源。然后,它将只允许对该类源路径下的文件进行文件访问。这还有一个很好的优点,我可以在应用程序开始时设置一次安全管理器,然后在输入和退出插件代码时更新它

这基本上解决了问题,但没有回答我的另一个问题:为什么URLClassLoader不能像它说的那样为我处理这个问题?我会把这个问题留一段时间,看看有没有人能回答这个问题。如果是这样,该人将得到公认的答案。否则,我将把它授予Ani B。前提是URLClassLoader文档是假的,并且他关于创建自定义SecurityManager的建议是正确的

PluginThread必须在PluginSecurityManager上设置classSource属性,该属性是类文件的路径。PlugUnsecurityManager现在看起来像这样:

package test.app;

public class PluginSecurityManager extends SecurityManager {
    private String _classSource;

    @Override
    public void checkPermission(Permission perm) {
        check(perm);
    } 

    @Override
    public void checkPermission(Permission perm, Object context) {
        check(perm);
    }

    private void check(Permission perm) {
        if (_classSource == null) {
            // Not running plugin code
            return;
        }

        if (perm instanceof FilePermission) {
            // Is the request inside the class source?
            String path = perm.getName();
            boolean inClassSource = path.startsWith(_classSource);

            // Is the request for read-only access?
            boolean readOnly = "read".equals(perm.getActions());

            if (inClassSource && readOnly) {
                return;
            }
        }

        throw new SecurityException("Permission denied: " + perm);
    }

    void setClassSource(String classSource) {
    _classSource = classSource;
    }
}

实现
SecurityManager
可能是最好的方法。您必须覆盖
checkPermission
。该方法将查看传递给它的
权限
对象,并确定某个操作是否危险。通过这种方式,您可以允许某些权限,而不允许其他权限

您能描述一下您使用的自定义
安全管理器吗?

来自文档:
创建URLClassLoader实例的线程的AccessControlContext将在随后加载类和资源时使用。

默认情况下,加载的类仅被授予访问创建URLClassLoader时指定的URL的权限。


URLClassLoader完全按照它所说的做,AccessControlContext是您需要查看的。基本上,AccessControlContext中引用的线程没有权限执行您认为它可以执行的操作。

在应用程序中运行一些Groovy脚本时,我使用以下方法。我显然希望防止脚本(有意或无意)运行System.exit

我以通常的方式安装java SecurityManager:

-Djava.security.manager -Djava.security.policy=<policy file>
我限制了Groovy脚本运行部分的功能:

list = AccessController.doPrivileged(new PrivilegedExceptionAction<List<Stuff>> () {
    public List<Stuff> run() throws Exception {
        return groovyToExecute.someFunction();
    }
}, allowedPermissionsAcc);
现在棘手的部分是找到正确的权限


如果您想允许访问某些库,您很快就会意识到,编写这些库时没有考虑到安全管理器,也没有很好地处理安全管理器,要找出它们需要的权限可能非常棘手。如果您想通过Maven Surefire插件运行UnitTests,或者在不同的平台(如Linux/Windows)上运行UnitTests,您将遇到更多的问题,因为行为可能会有所不同:-(.但这些问题是另一个主题

这是一个相关的问题,可能会有帮助::)是的,事实上我自己就链接到了这个问题。问题是,这里提出的解决方案是不完整的。它没有完全实现SecurityManager,这是这个问题的关键部分。它也没有解释为什么你一开始就需要一个,因为URLClassLoader声称默认情况下会为你处理这个问题。你知道不受信任的代码可能在
run
返回后在另一个线程中运行代码吗?我有一个非常类似的问题,我正在尝试解决这个问题。然而,PluginThread.run方法中是否存在一个大问题,即更改整个系统的安全管理器。如果这
package test.app;

class PluginThread extends Thread {
    PluginThread(Runnable target) {
        super(target);
    }

    @Override
    public void run() {
        SecurityManager old = System.getSecurityManager();
        PluginSecurityManager psm = new PluginSecurityManager();
        System.setSecurityManager(psm);
        psm.enableSandbox();
        super.run();
        psm.disableSandbox();
        System.setSecurityManager(old);
    }
}
package test.plugin;

public MyPlugin implements Plugin {
    @Override
    public void go() {
        new AnotherClassInTheSamePlugin(); // ClassNotFoundException with a SecurityManager
        doSomethingDangerous(); // permitted without a SecurityManager
    }

    private void doSomethingDangerous() {
        // use your imagination
    }
}
package test.app;

public class PluginSecurityManager extends SecurityManager {
    private String _classSource;

    @Override
    public void checkPermission(Permission perm) {
        check(perm);
    } 

    @Override
    public void checkPermission(Permission perm, Object context) {
        check(perm);
    }

    private void check(Permission perm) {
        if (_classSource == null) {
            // Not running plugin code
            return;
        }

        if (perm instanceof FilePermission) {
            // Is the request inside the class source?
            String path = perm.getName();
            boolean inClassSource = path.startsWith(_classSource);

            // Is the request for read-only access?
            boolean readOnly = "read".equals(perm.getActions());

            if (inClassSource && readOnly) {
                return;
            }
        }

        throw new SecurityException("Permission denied: " + perm);
    }

    void setClassSource(String classSource) {
    _classSource = classSource;
    }
}
-Djava.security.manager -Djava.security.policy=<policy file>
grant {
    permission java.security.AllPermission;
};
list = AccessController.doPrivileged(new PrivilegedExceptionAction<List<Stuff>> () {
    public List<Stuff> run() throws Exception {
        return groovyToExecute.someFunction();
    }
}, allowedPermissionsAcc);
private static final AccessControlContext allowedPermissionsAcc; 
static {    // initialization of the allowed permissions
    PermissionCollection allowedPermissions = new Permissions();
    allowedPermissions.add(new RuntimePermission("accessDeclaredMembers"));
    // ... <many more permissions here> ...

    allowedPermissionsAcc = new AccessControlContext(new ProtectionDomain[] {
        new ProtectionDomain(null, allowedPermissions)});
}