1

我试图禁止在 AccessController.doPriviliged() 方法中创建线程。下面的方法创建并运行线程。我用-Djava.security.manager 运行它。根据这个链接,如果 modifyThreadGroup 没有被授予,那么线程创建应该被禁止?

http://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html

谁能告诉我为什么会发生这种情况以及禁止使用 AccessController 创建线程的正确方法?

// .java.policy in $UserHome:

grant codeBase "file:/C:/-" {
    permission java.security.AllPermission;
};


public class ThreadTest {
  public void testModifyThreadGroup() {

    // grant no permissions
    Permissions perms = new Permissions();

    ProtectionDomain domain = new ProtectionDomain(
            new CodeSource( null, (Certificate[]) null ), perms );
    AccessControlContext _accessControlContext = new AccessControlContext(
            new ProtectionDomain[] { domain } );

    try {
        AccessController.doPrivileged(new PrivilegedExceptionAction(){
            @Override
            public Object run() {
                try {
                    // modifyThreadGroup not granted, so should not be able
                    // to call Thread constructor???
                    Thread t = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("Thread.run()");
                        }
                    });
                    t.run();
                } catch (Exception ex) {
                    System.out.println("Error running thread: " + ex);
                }
                return null;
        }}, _accessControlContext);
    } catch(Exception e) {
        System.out.println("Access Error running doPrivileged: " + e);
    }
  }
}
4

2 回答 2

3

创建或启动线程时所做的唯一检查是检查调用线程是否有权修改线程组。正如您可能认为的那样,这不会检查调用线程是否具有“modifyThreadGroup”权限。

相反,它的作用(默认情况下)是始终授予访问权限,除非所讨论的 ThreadGroup 是系统线程组,在这种情况下会检查“modifyThreadGroup”权限。有问题的 ThreadGroup 几乎从来都不是系统线程组。

您必须使用自己的实现来扩展 SecurityManager 并自己进行某种检查。您可能应该制定自己的新权限。作为一个例子,我使用现有的权限实现了一个 hack,我知道在给定默认策略的情况下线程将拥有(exitVM):

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;

public class QuickTest {

    public static class NoThreadsSecurityManager extends SecurityManager {

        public void checkAccess(ThreadGroup g) {
            super.checkAccess(g);
            checkPermission(new RuntimePermission("exitVM"));
        }

    }

    public static class SimpleRunnable implements PrivilegedExceptionAction<Object> {
        @Override
        public Object run() {
            try {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("Thread.run()");
                    }
                });
                t.start();
                t.join();
            } catch (Exception ex) {
                System.out.println("Error running thread: " + ex);
            }
            return null;
        }
    }

    public void testModifyThreadGroup() {

        // grant no permissions
        Permissions perms = new Permissions();

        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
        AccessControlContext _accessControlContext = new AccessControlContext(new ProtectionDomain[] { domain });

        try {
            AccessController.doPrivileged(new SimpleRunnable(), _accessControlContext);
        } catch (Exception e) {
            System.out.println("Access Error running doPrivileged: " + e);
        }

        new SimpleRunnable().run();

    }

    public static void main(String[] args) {
        System.setSecurityManager(new NoThreadsSecurityManager());
        new QuickTest().testModifyThreadGroup();
    }

}
于 2013-07-08T22:07:43.330 回答
2

在接受了 Pace 的回复后,我发现了一些其他人可能会觉得有用的东西。从您链接的文档中:“需要更严格策略的应用程序应覆盖此方法。如果此方法被覆盖,则覆盖它的方法应另外检查调用线程是否具有 RuntimePermission("modifyThreadGroup") 权限,如果所以,静默返回。这是为了确保授予该权限的代码(例如 JDK 本身)被允许操作任何线程。我发现在相关方法中检查“modifyThread”和“modifyThreadGroup”(您在其中检查“exitVM”)给出了所需的行为。

于 2014-10-17T19:31:37.833 回答