如何沙箱化Java程序

时间:2014-08-08 21:52:58

标签: java php multithreading ide classloader

我一直在尝试构建一个在线java编译器。我看了一些像this one这样的答案。但仍有一些我不明白的事情。

  1. 我在PHP中使用java -Djava.security.manager HelloWorld.class来运行用户的Java代码。但正如this one所说,我需要Run the untrusted code in its own thread。我真的需要构建线程吗?如果我不这样做,它会导致什么? (所有用户代码都存储在不同的文档中,但类名可能相同)

  2. 如果我成功实现了线程和类加载器,我应该将这两个类放在不同的文件中吗?比如说,一个文件中的线程,另一个文件中的类加载器?

  3. 如果我使用this one所说的方式(这是thread + classloader + securitymanager),这是否意味着我无法在命令行中编译代码?而不是它,我应该运行包含thread + classloader + securitymanager的Java文件并将一些变量传递给这个类?

  4. 对不起,请提出我的问题。我知道一点Java,我需要提出太多简单的事情。

1 个答案:

答案 0 :(得分:1)

java -Djava.security.manager -java.security.policy=filename.policy HelloWorld.class

如果filename.policy是硬盘驱动器上的文件,根本没有任何条目将“足够”沙箱代码并防止它在您的PC上进行恶意写入/读取。

仅仅运行它的问题是允许无限循环,它可能会消耗你所有的CPU能力而且永远不会停止。

对此的修复确实是为了创建一个新的不同程序,它创建一个新的Process,它启动并且只允许该Process在终止它之前存在一段时间(暴力)。

这是我为此制作的一些代码(从旧代码中删除):

class TestProcess {
    private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        List<String> out = new ArrayList<>();
        IntegerCallable ic = new TestProcess.IntegerCallable(out);
        int returnVal = timedCall(ic);
    }

    private static <T> T timedCall(Callable<T> c) throws InterruptedException, ExecutionException, TimeoutException {
        FutureTask<T> task = new FutureTask<>(c);
        THREAD_POOL.execute(task);
        return task.get(3, TimeUnit.SECONDS);
    }


    public static class IntegerCallable implements Callable<Integer> {
        private final List<String> output;
        private Process process;

        public IntegerCallable(List<String> out) {
            this.output = out;
        }

        public Integer call() throws Exception {
            ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec");
            pb.redirectErrorStream(true);
            process = pb.start();

            try (final Scanner scan = new Scanner(process.getInputStream())) {
                while (scan.hasNext())
                    output.add(scan.nextLine());
            }
            return process.exitValue();
        }
    }
}

需要根据您的需要修改专栏ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec");。该行在名为execCommand的文件夹中执行Exec.class文件,该文件夹也是exec.policy文件的位置,最多为64MB堆。