为什么java安全管理器既不禁止创建新的Thread()也不禁止启动它?

2022-09-04 08:18:04

您是否碰巧知道为什么Java安全管理器不禁止创建新线程或启动它们的解释?new FileWriter 位于安全管理器下,但 new Thread() 和 threadInstance.start() 都不是 uneder 安全管理器,可以调用。

  1. 禁止它不是很有用吗?
  2. 实施起来会不会很难?
  3. 或者创建和启动新线程与禁止它无关?

答案 1

无法定义一个安全策略来阻止代码使用标准 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”来控制代码是否可以创建线程。

因此,如果我们现在定义安全管理器的子类,如下所示:

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

当我们尝试创建新线程时,我们在 Test 类中遇到异常:

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

答案 2

在 Thread 构造函数中执行了访问检查,以查看调用方是否有权更改要将新线程添加到的 ThreadGroup。这就是实现安全策略以禁止创建新线程的方式。

(还有另一个关于创建线程组的检查...检查您是否有权将新组添加到其父组。

因此,要回答您的问题:

为什么java安全管理器既不禁止创建新的Thread()也不禁止启动它?

原因是 JVM 的当前安全策略允许父线程修改其 .您应该能够修改该策略设置以防止这种情况,从而防止创建子线程。ThreadGroup

禁止它不是有用吗?

是的。允许不受信任的代码创建/启动线程是不明智的,因为:1)一旦启动的线程就无法安全地被杀死,2)创建/启动大量线程可能会使JVM(也许还有操作系统)陷入瘫痪。

会很难实施吗?

从您的角度来看,只需更改策略即可。