Песочницу Java. Используя securitymanager, чтобы перенаправить ввод-вывод
В настоящее время я пытаюсь написать песочницу для запуска ненадежного кода Java. Идея состоит в том, чтобы изолировать приложение Java от доступа к файловой системе или сетевым сокетам. Решение, которое у меня есть на данный момент, переписано SecurityManager, который запрещает любой доступ к IO или сети.
теперь я хочу не запрещать, а перенаправлять вызовы в файловую систему, т. е. если приложение хочет написать "/главная/пользователя/приложения.txt" путь к файлу должен быть заменен что-то вроде "/ "темп" /trusted_folder/приложения.txt". Поэтому в основном я хочу разрешить приложениям доступ к файловой системе только в определенной папке и перенаправлять все остальные вызовы в эту папку.
Итак, вот метод из класса FileOutputStream, где SM спрашивается, есть ли разрешение на запись в данный путь.
 public FileOutputStream(File file, boolean append)
    throws FileNotFoundException
{
    String name = (file != null ? file.getPath() : null);
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkWrite(name);
    }
    if (name == null) {
        throw new NullPointerException();
    }
    fd = new FileDescriptor();
    fd.incrementAndGetUseCount();
    this.append = append;
    if (append) {
        openAppend(name);
    } else {
        open(name);
    }
}
очевидно, что SM не имеет доступа к FileOutputStream и не может изменить внутренний переменные в методе (например,имя или ) или как-то влияют на порядок выполнения, за исключением бросания SecurityException. Я понимаю, что доступ к внутренним полям является нарушением объектно-ориентированных принципов, я понимаю, что локальные переменные видны и существуют только внутри метода, где они были объявлены.
Итак, мой вопрос: есть ли способы разрешить Security Manager заменять вызовы в файловую систему? Если нет, есть ли другие подходы, которые я могу использовать для этого?
надеюсь, я достаточно ясно выразился.
4 ответов
SecurityManager не может этого сделать, он может только сказать да или нет.
Я могу придумать два варианта:
- сделайте что-нибудь на уровне ОС с файловой системой. Есть такие вещи, как chroot jails. Это будет прозрачно для приложения, но требует работы за пределами Java. 
- предоставьте API приложению, которое открывает FileOutputStream для них. Уровень API решает, где находятся файлы из, и это привилегировано (в терминах Security Manager), чтобы открыть файлы из любого места. Конечно, для этого требуется, чтобы изолированное приложение использовало ваш API вместо - java.io.Fileнапрямую. Но он также намного более гибкий, и в какой-то момент, вероятно, необходимо, чтобы приложение знало о песочнице и использовало sandbox API, как и на Java WebStart .
Теперь, что Java с открытым исходным кодом, вы можете загрузить исходный код FileOutputStream, измените его исходный код, чтобы применить любые ограничения, которые вы хотите, перекомпилируйте его, добавьте его в jar и добавьте этот JAR в путь к классу загрузчика JVM:
java -Xbootclasspath/p:myModifiedJavaClasses.jar sandbox.Main -run untrusted.Main
JVM теперь будет использовать вашу реализацию java.io.FileOutputStream вместо обычного одного.  Промыть и повторить для всех классов JSE, которые нуждаются в специальной логике перенаправления песочницы.  
Это не самый портативный и легко развернуть решение, поскольку оно требует" вне виртуальной машины " модификации параметров запуска, но в определенных ситуациях это решение может быть приемлемым и эффективным.
Я не думаю, что это можно сделать. Менеджер безопасности предназначен для запрета доступа к определенным операциям, а не для перенаправления ввода-вывода или других подобных действий.
даже если это возможно через некоторые серьезные размышления hackery, он, вероятно, не будет портативным между различными поставщиками jvm и даже различными операционными системами, работающими под одной и той же jvm. (это потому, что вам нужно будет манипулировать конкретными классами ОС).
то, что вы хотите сделать, следует попытаться сделать ниже уровень, см. chroot для linux и другие более тяжелые методы виртуализации.
Я думаю, что то, что вы пытаетесь сделать, уже было реализовано инженерами Wealthfront.
Вот их запись в блоге об этом:http://eng.wealthfront.com/2010/11/less-io-for-your-java-unit-tests.html
