我有一个Java应用程序,用户可以在其中加载第三方“插件”以增强用户体验。存在供这些插件使用的API,但出于安全考虑,应限制第三方软件访问内部应用程序类。插件的受限制的包将是“com.example”,而允许的是“com.example.api”。 API类确实调用了内部的混淆类。
在研究完这个之后,我遇到了几种SecurityManager的方法:checkMemberAccess(Class, int)和checkPackageAccess(String),这两种方法似乎都是实现目标的可行途径。但是,经过一些测试和进一步研究后,我发现checkMemberAccess仅适用于反射调用,而checkPackageAccess仅在类加载器调用loadClass时调用。
限制对包的访问的合理方法是什么(com.example,而不是com.example.api)?
答案 0 :(得分:2)
我建议为插件编写一个自定义类加载器,它隐藏了使用该类加载器加载的类中com.example
包的存在。通常类加载器委托给它们的父级,但是在野外有几个实现只会部分或根本不这样做。我相信,例如蚂蚁使用这种技术。当加载这样的类加载器时,任何链接链接禁止功能的类都将无法加载。或者,如果实现使用延迟链接,并且确实成功加载,则在执行禁用代码期间仍然会失败。
在拒绝插件链接时访问禁用包后,您可以使用SecurityManager通过反射拒绝运行时访问,并拒绝创建可能用于规避您的类加载器的新类加载器。
class RestrictingClassLoader extends URLClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (!name.startsWith("com.example.") || name.startsWith("com.example.api."))
return super.loadClass(name);
return findClass(name);
}
}
class RestrictingSecurityManager extends SecurityManager {
private boolean isRestricted() {
for (Class<?> cls: getClassContext())
if (cls.getClassLoader() instanceof RestrictingClassLoader)
return true;
return false;
}
// Implement other checks based on isRestricted().
}