使用带反射的安全管理器访问 jar 文件

Posted

技术标签:

【中文标题】使用带反射的安全管理器访问 jar 文件【英文标题】:Using a security manager with reflection accessing a jar file 【发布时间】:2018-09-16 14:39:17 【问题描述】:

在实现我的平台以能够使用反射动态加载 jar 文件后,我遇到了一个安全问题。 jar 文件可能是“危险的”并且包含可能影响事物的代码,因此我遇到了使用 SecurityManager 的问题。

我正在像这样加载 jar 文件(硬编码文件示例):

URLClassLoader clsLoader = URLClassLoader
    .newInstance(new URL[]  new URL("file:/C://Temp/SettingsApp.jar") );
Class<?> cls = clsLoader.loadClass("iezon.app.SettingsApp");
JPanel settingsApp = (JPanel) cls.newInstance();

我曾尝试像这样使用SecurityManager

try 
    SecurityManager sm = new SecurityManager();
    Object context = sm.getSecurityContext();
    sm.checkPermission(new AllPermission(), context);
    settingsAppPanel = (JPanel) cls.newInstance();
 catch (AccessControlException e) 
    e.printStackTrace();

AllPermission() 的测试有效并给了我这个例外:

java.security.AccessControlException: 访问被拒绝 ("java.security.AllPermission" "" "")

但是,我找不到有关如何将 jar 文件绑定到此安全管理器而不是当前平台的任何信息。我只是不希望 jar 文件能够在不首先请求用户可以接受的权限的情况下打开套接字等。

我偶然发现了BasicPermission,但是,这是一个抽象类,不能像AllPermission 那样被实例化,同样,我无法找到任何有关处理此问题的信息。任何帮助将不胜感激!

【问题讨论】:

似乎存在一个根本性的误解。无论您是否在某处调用sm.checkPermission(new AllPermission(), context);,都与安全性无关。所以用另一种权限替换AllPermission 是没有用的。要使用安全管理器,您必须通过System.setSecurityManager(…) 或通过启动选项安装它。此外,您必须决定是要实现安全管理器还是使用标准安全管理器并编写策略文件。无论哪种情况,您都不必实例化权限对象。 我根据您@Holger 的评论回答了这个问题 【参考方案1】:

正如 cmets 中提到的@Holger,使用安全管理器实现的唯一方法是动态创建策略。因此,当开发者将新应用上传到应用商店时,他会获得一组策略来声明他的应用使用。在应用程序上,然后将其反馈给用户,要求他们确认此策略(如果涉及套接字等,风险自负),然后创建一个策略并且应用程序可以运行:

if (!app.policyIsAgreedTo()) 
        if(readPolicy(app).get(0).equalsIgnoreCase("grant ")) 
            app.setPolicy(true);
         else 
            throw new Exception("App policy has not been agreed to.");
        
    

    if (app.policyIsAgreedTo()) 
        System.setProperty("java.security.policy", "file:/C:/Temp/" + app.getName() + ".policy");
        System.setSecurityManager(new SecurityManager());
        JPanel panel = (JPanel) app.getObject().newInstance();
        System.setSecurityManager(null);
        return panel;
    

    throw new Exception("App policy has not been agreed to.");

政策是这样创建的:

public static void createPolicy(ArrayList<String> policies, App app) 

    try 
        FileWriter fileWriter =
                new FileWriter("C:/Temp/" + app.getName() + ".policy");
        BufferedWriter bufferedWriter =
                new BufferedWriter(fileWriter);

        bufferedWriter.write("grant ");
        bufferedWriter.newLine();

        for(String policy : policies) 
            bufferedWriter.write("    permission java.lang.RuntimePermission \"" + policy + "\";");
            bufferedWriter.newLine();
        

        bufferedWriter.write(";");
        bufferedWriter.close();

     catch(IOException ex) 
        ex.printStackTrace();
    

应用程序对应用程序商店进行 API 调用,收集应用程序所需的权限,然后使用 ArrayList 中的权限调用简单的createPolicy(),即:

new ArrayList<String>()  add("setSecurityManager"); ; // Etc...

【讨论】:

当您需要安全性时,您必须在代码在 JVM 中的整个时间内保持已安装的安全性管理。在调用构造函数后立即调用System.setSecurityManager(null); 意味着,您只有在构造函数执行时才具有安全性。如果你想要动态策略,你必须实现自己的安全管理器,它支持扩展当前策略。你不能通过卸载当前的安全管理器来做到这一点,即使是很短的时间。 我能否覆盖checkPermission() 方法,将super.checkPermission() 包裹在instanceof() 周围并通过应用程序?对于每个应用程序,将属性设置为该特定策略? @Holger 那会让安全管理器附加到该进程吗? @Holger IE:像这样的峰会System.setSecurityManager(new SecurityManager() @Override public void checkPermission(java.security.Permission perm) Object context = this.getSecurityContext(); if(context.getClass() == app.getClass()) super.checkPermission(perm); ); 但在超级通话之前加载应用策略 Would adding a codeBase 到包 iezon.app.* 在政策中工作?

以上是关于使用带反射的安全管理器访问 jar 文件的主要内容,如果未能解决你的问题,请参考以下文章

反射从入门到精通

Android AAR 文件防止反射

c#的属性和反射,大约是啥回事

如何禁用 Java 安全管理器?

无法访问 PUBLIC 架构中的表

小程序有时会自动关闭