使用安全管理器的性能损失(如果有的话)是什么



使用SecurityManager时是否存在性能损失?

我需要以下内容:

public class ExitHelper {
    public ExitHelper() {
        System.setSecurityManager(new ExitMonitorSecurityManager());
    }
    private static class ExitMonitorSecurityManager extends SecurityManager {
        @Override
        public void checkPermission(Permission perm) {}
        @Override
        public void checkPermission(Permission perm, Object context) {}
        @Override
        public void checkExit( final int status ) {
            // this is the part I need and I don't care much about the performance issue of this method
        }
}

这会对我的程序产生很大的影响吗?

例如,

程序确实打开了很多文件。如果我启用SecurityManager并在其中添加一些登录,我就可以多次调用这些方法。真的很多。如此之多,以至于在这两种方法的日志记录中丢失了正常的日志记录。因此,将SecurityManager放入适当的位置似乎意味着要进行大量的调用。它会比默认的SecurityManager慢吗?(默认有吗?)

这是如何工作的?程序的哪一部分将被检查权限,多久检查一次?我关心的两个checkPermission(…)方法。

有性能损失,但可能很小,因为:

  • 它仅适用于当您尝试某些需要权限检查的活动时。
  • 大多数需要权限检查的操作都是昂贵的操作(IO,网络访问等),因此安全检查的开销可能会占总运行时的相当低的百分比。
  • 支票本身可以非常便宜地制作
特别要注意的是,在Java库代码中,用于安全检查的调用代码通常是非常轻量级的,例如:
 SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkXXX(argument,  . . . );
 }

如果您的安全管理器代码本身同样轻量级,那么安全检查的运行时成本应该可以忽略不计。然而,我会避免在SecurityManager中放置任何日志代码——这将是昂贵的,并且可能属于应用程序代码的更高级别。

如果你想绝对最小化你不关心的权限的安全管理器的开销,那么你应该覆盖特定的checkXXX方法,你不需要这样做:

@Override 
public void checkRead(String file) {
  // empty method as we are happy to allow all file reads
}

最终,您将不得不针对您的特定情况进行基准测试,但"直觉"的答案将是您不应该真正担心它。

是的,存在性能损失。如果你担心它,你唯一的办法就是衡量它,看看惩罚是否太高。

对于您的特定用例,一个潜在的解决方案是,如果您可以缩小需要时的范围。您显然希望阻止一些您无法控制的代码退出应用程序。如果您知道何时可以调用代码,那么您可以在调用期间设置安全管理器(注意,这里需要注意线程影响,因为安全管理器设置是全局的),例如:

System.setSecurityManager(new ExitMonitorSecurityManager());
try {
  // ... do protected op here ...
} finally {
  System.setSecurityManager(null);
}
更新:

向那些稍后可能会看到这个答案的人澄清,这个答案是而不是为处理潜在的恶意代码而设计的。在这种情况下,适当配置的SecurityManager应该在任何时候都处于适当位置。这个答案假设OP正在尝试处理一个编写得很差的第三方库,该库在某个定义良好的时间点对System.exit()进行了不幸的调用。

在实现安全管理器问题之后,我有一些经验证据可以在这里提供:

与NO安全管理器相同的java SecurityManager,除了System.exit的单个检查调整

这个匿名内部类对性能的影响是巨大的:
        System.setSecurityManager(new SecurityManager() {
            @Override
            public void checkPermission(Permission perm) {
                return; // no security manager behaviour
            }
            @Override
            public void checkPermission(Permission perm, Object context) {
                return; // no security manager behaviour
            }
            @Override
            public void checkExit(int status) {
                Thread.dumpStack();
                super.checkExit(status);
            }
        });

我在Eclipse中启动应用程序后的经验是它明显变慢了,我在同事的PC上也证实了这一点。

所以我觉得"可忽略不计"可能是一种轻描淡写的说法(我的用例甚至没有实际执行任何检查!)。

请把这当作一个轶事,事实并非如此。

作为另一个边注:我创建了一个final类,它对所有方法都进行了什么都不做的检查,以避免实例化权限对象等(不鼓励jit编译器对它进行热启动)。使用这种方法,对性能的影响确实很小。因此,对于那些只想添加一些特定检查(而不依赖于java策略)的人来说,这实际上没有什么影响:

public final class SystemExitTraceSecurityManager extends SecurityManager {
    @Override
    public final void checkAccept(String host, int port) {
    }
    @Override
    public final void checkAccess(Thread t) {
    }
    @Override
    public final void checkAccess(ThreadGroup g) {
    }
    @Override
    public final void checkAwtEventQueueAccess() {
    }
    @Override
    public final void checkConnect(String host, int port) {
    }
    @Override
    public final void checkConnect(String host, int port, Object context) {
    }
    @Override
    public final void checkCreateClassLoader() {
    }
    public final void checkDelete(String file) {
    };
    @Override
    public final void checkExec(String cmd) {
    }
    public final void checkExit(int status) {
        Thread.dumpStack();
    };
    @Override
    public final void checkLink(String lib) {
    }
    @Override
    public final void checkListen(int port) {
    }
    @Override
    public final void checkMemberAccess(Class<?> clazz, int which) {
    }
    @Override
    public final void checkMulticast(InetAddress maddr) {
    }
    @Override
    public final void checkMulticast(InetAddress maddr, byte ttl) {
    }
    @Override
    public final void checkPackageAccess(String pkg) {
    }
    @Override
    public final void checkPackageDefinition(String pkg) {
    }
    @Override
    public final void checkPermission(Permission perm) {
    }
    @Override
    public final void checkPermission(Permission perm, Object context) {
    }
    @Override
    public final void checkPrintJobAccess() {
    }
    @Override
    public final void checkPropertiesAccess() {
    }
    public final void checkPropertyAccess(String key) {
    };
    @Override
    public final void checkRead(FileDescriptor fd) {
    }
    @Override
    public final void checkRead(String file) {
    }
    @Override
    public final void checkRead(String file, Object context) {
    }
    @Override
    public final void checkSecurityAccess(String target) {
    }
    @Override
    public final void checkSetFactory() {
    }
    @Override
    public final void checkSystemClipboardAccess() {
    }
    @Override
    public final boolean checkTopLevelWindow(Object window) {
        return true;
    }
    @Override
    public final void checkWrite(FileDescriptor fd) {
    }
    @Override
    public final void checkWrite(String file) {
    }
}

相关内容

最新更新