UNI*_*orn 3 java securitymanager
嗨,SecurityManager 专家们;-)
我编写了一个小型插件框架,它使用单独的隔离类加载器加载插件。为了成功取消部署插件,重要的是要确保应用程序不保留对插件类加载器加载的类的引用。
Java 中有一个称为 shutdown hook 的功能,它允许客户端代码注册一个线程,该线程在 JVM 被请求关闭时执行。这意味着 JVM 可能会持有对插件类加载器加载的类的引用。
我的第一次尝试是安装一个拒绝添加关闭挂钩的 SecurityManager。这完全有效并拒绝所有添加关闭挂钩的尝试。有趣的是,我意识到,并不是插件本身想要添加关闭挂钩。SunFontManager该插件只是通过加载字体来触发 AWT/Swing 内部机制(准确地说:) 。反过来,它又SunFontManager添加了 shutdown hook,以便在 JVM 退出时执行一些内部处理。我不想否认插件加载字体(因为它必须这样做),并且我不想否认 Java 内部添加它们的东西。
对我来说,我似乎必须向代码授予比通常更多的权限(如果sun.*|java.*|javax.*包位于堆栈跟踪中..uuuhmm...丑陋)。但这打破了安全框架的约定,该约定假定客户端代码不能比调用它的代码拥有更多的特权。
我如何区分不是插件代码而是 Java 内部想要做某事?或者有没有其他方法可以确保不会因为否认某些事情而破坏内部结构?
为了让事情更清楚,以下是我的应用程序中实际发生的情况。我安装了一个自定义 SecurityManager,它应该拒绝addShutdownHook由插件直接执行,但如果作为 Java 内部类的副作用执行,则不应拒绝这些调用。
上下文: 调用:
----------------------------------------------------------
App类加载器应用程序
|
PluginClassloader PluginObject.init()
|
AppClassloader Font.create()
|
AccessController.doPrivileged(...) {
Runtime.addShutdownHook(...)
}
SecurityManager 是使用System.setSecurityManager()以下命令安装的:
@Override
public void checkPermission(java.security.Permission perm) {
if (perm.getName().equals("shutdownHooks")) {
if (threadContextClassLoaderIsPluginClassLoader()) {
throw new SecurityException("Installing shutdown hooks is not allowed.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
尽管 theaddShutdownHook是在doPrivileged-block 内部调用的,但 mySecurityManager是被调用的。我错过了什么吗?我应该自己检查特权上下文吗?
我发现我完全误解了Java安全概念。我想为插件代码构建一个沙箱,以便它始终在受限制的环境中运行,我可以控制它所拥有的权限。应用程序应始终在授予完全访问权限的情况下运行。
以下是如何为单独的类加载器加载的类构建沙箱:
java.lang.SecurityManager以根据权限允许或拒绝操作,那么您可能做错了!您只需java.lang.SecurityManager执行此操作即可安装默认值System.setSecurityManager(new SecurityManager());。现在,您可以使用 Java 默认值获得有效的访问控制。向应用程序授予所有权限加载插件的应用程序应获得完全访问权限。这是因为我们相信自己。我通过使用授予所有访问权限的策略文件启动我的应用程序解决了这个问题。我认为应用程序启动时需要策略文件,因为 AppClassLoader 需要为类创建正确的保护域。使用 JavaVM 参数启动主应用程序java.security.policy=<URL-TO-POLICY>,其中<URL-TO-POLICY指向以下策略文件:
grant {
permission java.security.AllPermission;
};
自定义策略实施我们需要在应用程序启动后安装自定义策略。我们希望将主应用程序(在授予完全访问权限的情况下运行)和插件(我们想要限制哪些权限)的权限分开。这些插件应该在具有精心挑选的权限的沙箱中运行。为了实现这一点,以下是自定义策略的实现:
class SandboxPolicy extends Policy {
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
// Decide if the plugin permissions are needed or full access can be granted using all permissions.
if (isPlugin(domain)) {
return pluginPermissions();
} else {
return applicationPermissions();
}
}
private boolean isPlugin(ProtectionDomain domain) {
// Identify the classloader of the protection domain
// The PluginClassLoader is assumed to be the one that loaded
// the plugin
return domain.getClassLoader() instanceof PluginClassLoader;
}
private PermissionCollection pluginPermissions() {
// Empty permissions = No permissions
// This is not the point to add plugin permissions
return new Permissions();
}
private PermissionCollection applicationPermissions() {
// Grant full access to the application
Permissions permissions = new Permissions();
permissions.add(new AllPermission());
return permissions;
}
}
Run Code Online (Sandbox Code Playgroud)每个类加载器的保护域 类加载器负责为ProtectionDomain加载代码的每个源创建一个保护域。保护域指定将授予代码的权限。我们必须修改类加载器添加到保护域的权限集。为此,让您的 PluginClassloader 扩展java.security.SecureClassLoader. java.security.SecureClassLoader.getPermissions(CodeSource)然后按以下方式重写该方法:
@Override
protected PermissionCollection getPermissions(CodeSource codeSource)
{
PermissionCollection pc;
// The SecureClassloader per default grants access to read resources from the source JAR.
// This is useful. Call super to get those permissions:
pc = super.getPermissions(codeSource);
// At this point you can extend permissions.
// For example grant read access to a file.
pc.add(new FilePermission("path\\file", "read"));
return (pc);
}
Run Code Online (Sandbox Code Playgroud)笔记:查看政策实施情况并查看我的评论// This is not the point to add plugin permissions。政策将被询问AccessController是否可以授予许可。如果在这里添加权限,那么你能从调用者那里得到的信息就非常有限。我不建议在这里计算和添加任何权限。类加载器是您可以根据代码源添加权限的地方。我建议在这里添加权限。它们在保护域中变得可见,您可以轻松观察 AccessController 对这些保护域执行的操作。
特权操作
我的问题还有一部分我想回答。
有趣的是,我意识到,并不是插件本身想要添加关闭挂钩。该插件只是通过加载字体来触发 AWT/Swing 内部(准确地说:SunFontManager)。
有些操作将作为插件代码的副作用执行。类org.plugin.A可以触发 Swing/AWT 内部来添加关闭挂钩。在这种情况下,我们不想否认这一点。Java 类在应用程序的范围内,并且应该获得完全访问权限。插件代码可能受到限制,直接添加关闭挂钩应该会失败并显示SecurityException. 这是 的常见用例java.security.AccessController.doPrivileged(PrivilegedAction<T>)。特权操作可确保AccessController仅考虑最后一个堆栈帧的保护域。AWT/Swing 在特权操作中添加其关闭挂钩,因此允许这样做,因为执行此操作的类的保护域设置了完全访问权限。请参阅 的任何文档java.security.AccessController以了解有关特权操作的更多信息。
| 归档时间: |
|
| 查看次数: |
2045 次 |
| 最近记录: |