我正在弄清楚如何在没有权限的情况下运行外部代码(来自其他JAR),以免损害我的系统。我几乎可以正常工作了,但是我发现一个奇怪的情况,对System.exit(0)的调用仍然会杀死整个系统。

这个想法是,在多线程环境中将加载不同的JAR,因此成功System.exit(0)大约是可能发生的最糟糕的情况,其中包括服务器上的许多其他安全风险。

我有以下代码(在SSCEE中):

public class RestrictAccessControlContext {
    private static final PermissionCollection ALLOWED_PERMISSIONS = new Permissions();
    static {
        //add permissions
    }
    private static final AccessControlContext RESTRICTED_ACCESS_CONTROL_CONTEXT =
        new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, ALLOWED_PERMISSIONS)});

    private static void executeSandboxed(final Runnable runnable) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<?> future = executorService.submit(() -> {
            AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
                runnable.run();
                return null;
            }, RESTRICTED_ACCESS_CONTROL_CONTEXT);
        });
        try {
            future.get();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException ex) {
            throw new RuntimeException(ex.getCause());
        } finally {
            executorService.shutdown();
        }
    }

    public static void main(String[] args) {
        executeSandboxed(() -> {
            AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
                System.exit(0);
                return null;
            });
        });
    }
}

需要哪个作为VM参数运行:

-Djava.security.manager -Djava.security.policy = src / java.policy

其中java.policy是:
grant {
    permission java.security.AllPermission;
};

这个想法是我自己的代码仍然具有完全权限,但是沙盒代码具有受限(在这种情况下:无)权限。

但是,在给定的示例中,它只是退出,请注意,main方法的以下变体确实起作用:
public static void main(String[] args) {
    executeSandboxed(() -> System.exit(0));
}


public static void main(String[] args) {
    executeSandboxed(() -> new Thread(() -> System.exit(0)).start());
}

我在这里做错了什么,为什么以前曾经被限制过,但为什么可以执行一个引发权限的AccessController.doPrivileged调用呢?我希望以下其中一项是正确的:
  • 可以给特定的权限来调用AccessController.doPrivileged
  • AccessController.doPrivileged块中,权限将是“父” AccessControlContext与给定权限的交集。

  • 这两个选项都会导致给定的代码正确地抛出AccessControlException,但是没有发生,为什么会这样呢?

    最佳答案

    您没有任何沙盒代码。您的具有完全权限的代码正在使用它们。未经相关许可的代码将无法退出。解决方案应该是使用不受信任的ProtectionDomain加载不受信任的代码。

    拥有提高许可的权限将毫无意义。这相当于拥有所有权限。

    在OpenJDK内部,有一种doPrivileged变体,它允许交叉权限,但是当存在多个不信任源时,它用于降低权限。

    10-08 16:20