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

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

  • Не было бы полезно запретить это?
  • Было бы трудно реализовать?
  • Или создание и запуск новой темы не так уж важно, чтобы запретить ее?

Ответ 1

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

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

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

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

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

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

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

Было бы трудно реализовать?

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

Ответ 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 выполняет только проверку прав, если код пытается создать поток в корневой группе ThreadGroup. В то же время SecurityManager getThreadGroup mehtod всегда возвращает текущую группу потоков Thread, которая никогда не будет основной группой потоков, поэтому разрешение на создание нового потока всегда будет предоставлено.

Один из способов обойти это - подкласс 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")