我试图禁止在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);
}
}
}
答案 0 :(得分:3)
创建或启动线程时唯一的检查是检查并查看调用线程是否有权修改线程组。您可能认为这不会检查调用线程是否具有“modifyThreadGroup”权限。
相反它的作用(by default)总是授予访问权限,除非有问题的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();
}
}
答案 1 :(得分:2)
在接受Pace的回应后,我发现其他人可能觉得有用的东西。从您链接的文档:“需要更严格的策略的应用程序应该覆盖此方法。如果重写此方法,覆盖它的方法应另外检查调用线程是否具有RuntimePermission(”modifyThreadGroup“)权限,如果所以,默默地返回。这是为了确保允许授予该权限的代码(例如JDK本身)操纵任何线程。“我发现在相对方法(你检查'exitVM')中检查'modifyThread'和'modifyThreadGroup'给出了所需的行为。