如果有的话,使用SecurityManager会有什么性能损失

时间:2011-11-22 17:10:48

标签: java security securitymanager

使用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(...)方法。

3 个答案:

答案 0 :(得分:7)

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

  • 仅当您尝试某种形式的需要权限检查的活动时才适用。
  • 大多数需要权限检查的操作都是昂贵的操作(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
}

最终你必须根据你的具体情况进行基准测试,但“直觉”的答案是你不应该真的担心它。

答案 1 :(得分:2)

是的,会有性能损失。如果你担心它,你唯一的办法是衡量它,看看惩罚是否过高。

针对您的特定用例的一个可能的解决方案是,如果您可以缩小其需要的范围。你显然想要从退出应用程序中停止一些你无法控制的代码。如果您知道何时可以调用该代码,那么您可以在该调用期间设置安全管理器(注意,由于安全管理器设置是全局的,因此您需要了解线程影响),例如:

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

更新:

向那些可能稍后回答此问题的人澄清,这个答案是设计用于处理潜在的恶意代码。在这种情况下,应始终将配置适当的SecurityManager 。这个答案假设OP正在尝试处理写得不好的第三方库,该库在一些明确定义的时间点对System.exit()进行了不幸的调用。

答案 2 :(得分:2)

在实施安全管理员问题之后,我有一些经验证据可以在这里做出贡献:

A java SecurityManager that is identical to NO security manager except for a single check adjustment for 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中也证实了这一点。

所以我觉得“可以忽略不计”可能是轻描淡写(我的用例甚至没有实际执行任何检查!)。将此视为一种轶事,事实并非如此。

另一方面注意:我创建了一个最后一个类,对ALL方法进行无操作检查,以避免实例化权限对象等(最后鼓励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) {
    }
}