【问题标题】:What's the performance penalty, if any, of using a SecurityManager使用 SecurityManager 的性能损失是多少(如果有的话)
【发布时间】:2012-01-04 01:44:07
【问题描述】:

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

【问题讨论】:

标签: java security securitymanager


【解决方案1】:

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

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

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

更新:

为了向稍后可能会回答此答案的人澄清,此答案并非旨在处理潜在的恶意代码。在这种情况下,应始终使用适当配置的 SecurityManager。此答案假定 OP 正在尝试处理编写不佳的第三方库,该库在某个明确定义的时间点不幸调用 System.exit()。

【讨论】:

  • Nooooooooooo!!!!!!您不知道何时可以调用代码。除了你可能有多个线程你可能试图同时运行不受信任的代码之外,恶意代码可能会运行终结器。
  • @TomHawtin-tackline - 嗯?如果您知道您将要调用的特定库调用执行了您不想要的操作,那么您可以使用类似的方法(同意由于各种原因它并不理想)。这是假设您没有运行恶意代码,只是行为不佳的代码。如果您正在运行潜在的恶意代码,那么您应该有一个全职的 SecurityManager,故事结束。很确定 OP 指的是前一种情况,而不是后者。
  • @TomHawtin-tackline - 我已经更新了答案以澄清上下文。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

    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 上证实了这一点。

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

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

    【讨论】:

    • 注意:由于JEP 232,从 JDK 9 开始,性能影响不应该那么严重。
    猜你喜欢
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2010-10-22
    • 1970-01-01
    • 2011-04-06
    • 2016-12-20
    相关资源
    最近更新 更多