почему диспетчер безопасности java не запрещает ни создавать новый Thread(), ни запускать его?

Вы случайно не знаете объяснение, почему диспетчер безопасности Java не запрещает создавать новые потоки или запускать их? новый FileWriter находится под управлением менеджера безопасности, но ни new Thread(), ни threadInstance.start() не являются менеджером безопасности uneder, и их можно вызвать.

  1. Не лучше ли запретить?
  2. Сложно будет реализовать?
  3. Или создание и запуск новой темы не настолько актуально, чтобы запрещать ее?

person bastiat    schedule 07.04.2013    source источник
comment
Какой язык программирования?   -  person a_horse_with_no_name    schedule 08.04.2013
comment
java, я добавил в тему и описание.   -  person bastiat    schedule 08.04.2013


Ответы (2)


Принятый ответ неверен: невозможно определить политику безопасности, которая не позволит коду создавать и запускать новый поток с использованием стандартного Java SecurityManager.

Допустим, у вас есть следующий код:

public class Test {
  public static void main(String [] args) {
    System.out.println(System.getSecurityManager() != null ? "Secure" : "");
    Thread thread = new Thread(
      new Runnable() { 
        public void run() {
          System.out.println("Ran");
        }
    });
    thread.start();
  }
}

и вы запускаете его с помощью следующей команды:

java -Djava.security.manager -Djava.security.policy==/dev/null Test

он будет работать нормально и выводить:

Secure
Ran

даже несмотря на то, что мы установили политику безопасности на /dev/null, что даст нулевые разрешения для любого кода. Поэтому невозможно предоставить меньше разрешений, чтобы предотвратить создание этого потока кодом.

Это связано с тем, что стандартный java.lang.SecuritManager выполняет проверку разрешений только в том случае, если код пытается создать поток в корневой группе потоков. В то же время метод getThreadGroup SecurityManager всегда возвращает группу потоков текущего потока, которая никогда не будет корневой группой потоков, поэтому разрешение на создание нового потока всегда будет предоставлено.

Один из способов обойти это — создать подкласс java.lang.SecurityManager и переопределить метод getThreadGroup, чтобы он возвращал корневую группу ThreadGroup. Это позволит вам контролировать, может ли код создавать потоки на основе того, имеет ли он java.lang.RuntimePermission «modifyThreadGroup».

Итак, если мы теперь определим подкласс SecurityManager следующим образом:

public class ThreadSecurityManager extends SecurityManager { 

  private static ThreadGroup rootGroup;

  @Override
  public ThreadGroup getThreadGroup() {
    if (rootGroup == null) {
      rootGroup = getRootGroup();
    }
    return rootGroup;
  }

  private static ThreadGroup getRootGroup() {
    ThreadGroup root =  Thread.currentThread().getThreadGroup();
    while (root.getParent() != null) {
     root = root.getParent();
    }
    return root;
  }
}

а затем снова запустите нашу команду, но на этот раз указав наш подкласс ThreadSecurityManager:

java -Djava.security.manager=ThreadSecurityManager -Djava.security.policy==/dev/null Test

Мы получаем исключение в нашем тестовом классе, когда пытаемся создать новый поток:

Exception in thread "main" java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "modifyThreadGroup")
person alphaloop    schedule 25.06.2015

В конструкторе Thread выполняется проверка доступа, чтобы узнать, есть ли у вызывающего объекта разрешение на изменение ThreadGroup, в которую будет добавлен новый поток. Именно так вы бы реализовали политику безопасности, чтобы запретить создание новых потоков.

(И есть еще одна проверка создания ThreadGroups... которая проверяет, есть ли у вас разрешение на добавление новой группы к ее родительской группе.)

Итак, чтобы ответить на ваши вопросы:

Почему диспетчер безопасности java не запрещает ни создавать новый Thread(), ни запускать его?

Причина в том, что текущая политика безопасности вашей JVM позволяет родительскому потоку изменять свои файлы ThreadGroup. Вы должны иметь возможность изменить этот параметр политики, чтобы предотвратить это и, следовательно, предотвратить создание дочерних потоков.

Не было бы полезно запретить это?

Это. Неразумно разрешать ненадежному коду создавать/запускать потоки, потому что: 1) однажды запущенные потоки нельзя безопасно убить, и 2) создание/запуск большого количества потоков может поставить JVM (и, возможно, ОС) на колени.

Сложно будет реализовать?

С вашей точки зрения, просто измените политику.

person Stephen C    schedule 07.04.2013
comment
Есть много способов поставить JVM на колени. Вам нужно будет предоставить ненадежному коду доступ по крайней мере к некоторым потокам. Очень полезно иметь возможность создавать темы. - person Tom Hawtin - tackline; 08.04.2013
comment
@Tom Вам обычно не нужно предоставлять доступ к потокам, но в этом случае вам часто приходится предоставлять доступ к замещающим средствам. Это было бы не так уж плохо, за исключением того, что обработка асинхронного ввода-вывода в Java все еще не очень сильна. - person Donal Fellows; 08.04.2013
comment
каков сценарий, в котором я могу получить исключение при создании нового потока в диспетчере безопасности? Я пробовал в своем собственном основном java -Djava.security.manager -Djava.security.policy=app.policy -cp bin pl.com.App с пустым app.policy и под Tomcat с (-security включен) в моем сервлете (в catalina.policy нет разрешения на поток), но я всегда могу создать и начать новый поток без исключения. - person bastiat; 09.04.2013
comment
Причина в том, что текущая политика безопасности вашей JVM позволяет родительскому потоку изменять свою ThreadGroup — где это задокументировано? установка policymanager по умолчанию в большинстве случаев состоит в том, чтобы запретить все, что явно не разрешено - person bastiat; 09.04.2013
comment
Проверка безопасности описана здесь: docs.oracle.com/javase/6/docs/api/java/lang/ - person Stephen C; 09.04.2013