1.一种在Java虚拟机中安全运行第三方类的方法,利用Java虚拟机提供的自定义类加载器的技术来控制第三方代码的本地模块和类的加载,只允许第三方代码加载和使用系统提供的已封装好业务逻辑的类,第三方代码对外部资源的访问只能通过上述系统提供的已封装好的业务逻辑类的接口执行,第三方代码本身不能直接访问外部资源,其特征在于,该方法包括:
创建自定义类加载器,所述自定义类加载器的父加载器为Java虚拟机当前线程的类加载器;
通过所述自定义类加载器来加载第三方类,即需要访问外部资源的业务逻辑封装于单独的功能类中,自定义类加载器将直接由其父加载器加载功能类,由此功能类中再加载使用其它类时将直接使用父加载器,从而安全地绕过自定义类加载器的限制;由所述自定义类加载器判断是否允许所述第三方类加载特定的系统类;
如果允许,则所述自定义类加载器委托其父加载器加载所述系统类;
若不允许,则抛出异常,从而控制所述第三方类中所能使用的类。
2.根据权利要求1所述的方法,其特征在于,根据需要,能够同时创建多个所述自定义类加载器以执行多份所述第三方类。
3.根据权利要求1所述的方法,其特征在于,关于所述第三方类所允许访问的类和/或所不允许访问的类的信息存放在所述自定义类加载器能够找到的存放位置。
4.根据权利要求3所述的方法,其特征在于,所述信息存放在特定文件中,或所述信息存放在数据库中,或所述信息直接写入在程序代码中。
5.根据权利要求2所述的方法,其特征在于,所述自定义类加载器加载所述第三方类时,确定所述第三方类可使用和/或不可使用的类。
6.根据权利要求1-5之一所述的方法,其特征在于,如果所述自定义类加载器判断出所述第三方类加载不允许加载的类时,抛出异常。
7.根据权利要求2所述的方法,其特征在于,分别采用不同的加载器来分别加载所述第三方类以防止恶意访问。
一种在Java虚拟机中安全运行第三方代码的方法\n技术领域\n[0001] 本发明涉及信息安全领域,特别涉及一种安全运行不可控的第三方代码的方法。\n背景技术\n[0002] 软件或服务器往往需要允许用户执行自定义的代码以实现高度的可定制性或安全性。但是由于第三方编写的代码的不可控性,限制其运行环境以保护服务器资源或上层软件的正常运行就成了一个很重要的问题。\n[0003] JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。\n[0004] 在JVM中使用一个类时,该类的加载过程是唯一可以在外部进行干预的,这可以通过JVM提供的自定义类加载器来实现。通常JVM中引入自定义类加载器的主要目的是实现代码的热部署,如OSGi系统等。OSGi(Open Service Gateway Initiative)技术是面向Java的动态模型系统。OSGi服务平台向Java提供服务,这些服务使Java成为软件集成和软件开发的首选环境。OSGi技术提供允许应用程序使用精炼、可重用和可协作的组件构建的标准化原语。这些组件能够组装进一个应用和部署中。\n[0005] JVM虚拟机提供的安全性主要通过虚拟机的安全策略文件实现,通过安全策略文件控制JVM中类对资源的访问(如文件系统和网络资源等)。但是在实际应用中,往往需要控制第三方代码本身不能直接访问一些外部资源(如文件、网络和一些本地模块的加载等),但是可以通过调用本地提供的方法来访问,而且JVM同时运行多个不同的第三方代码时还要实现代码间的相互隔离,这时只通过在JVM启动时静态地提供一个安全策略文件很难实现。\n发明内容\n[0006] 有鉴于此,本发明提供了一种在JVM上安全运行第三方代码的方法,利用JVM提供的自定义类加载器的技术来控制第三方代码的本地模块和类的加载,只允许第三方代码加载和使用系统提供的已封装好业务逻辑的类,第三方代码对外部资源的访问只能通过上述系统提供的已封装好的业务逻辑类的接口执行,第三方代码本身不能直接访问外部资源,从而实现安全访问外部资源。\n[0007] 根据本发明,提供一种在Java虚拟机中安全运行第三方类的方法,该方法包括:\n[0008] 创建自定义加载器,所述自定义加载器的父加载器为Java虚拟机当前线程的类加载器;\n[0009] 通过所述自定义加载器来加载第三方类,由所述自定义加载器判断是否允许所述第三方类加载特定的系统类;\n[0010] 如果允许,则所述自定义加载器委托其父加载器加载所述系统类;\n[0011] 若不允许,则抛出异常,从而控制所述第三方类中所能使用的类。\n[0012] 根据本发明的一个方面,根据需要,能够同时创建多个所述自定义加载器以执行多份所述第三方类。\n[0013] 根据本发明的一个方面,关于所述第三方类所允许访问的类和/或所不允许访问的类的信息存放在所述自定义类加载器能够找到的存放位置。\n[0014] 根据本发明的一个方面,所述信息存放在特定文件中,或所述信息存放在数据库中,或所述信息直接写入在程序代码中。\n[0015] 根据本发明的一个方面,所述自定义类加载器加载所述第三方类时,确定所述第三方类可使用和/或不可使用的类。\n[0016] 根据本发明的一个方面,如果所述自定义加载器判断出所述第三方类加载不允许加载的类时,抛出异常。\n[0017] 根据本发明的一个方面,分别采用不同的加载器来分别加载所述第三方类以防止恶意访问。\n附图说明\n[0018] 图1为按照本发明的一种在JVM上安全运行第三方代码的方法的一优选实施例的流程示意图。\n[0019] 图2为图1所示实施例中结构框图。\n具体实施方式\n[0020] 当JVM需要加载第三方代码时,创建一个自定义的类加载器,其父加载器设置为JVM当前线程的默认类加载器(根据本发明的一个实施例,通常就是SystemClassLoader),通过自定义类加载器的一个实例来加载第三方代码。在自定义类加载器中通过一个可使用类的列表(或不可使用类的列表)来控制第三方代码中外部类的使用,自定义类加载器的功能如下:\n[0021] 1、对于允许使用的本地模块中的类(如java.lang.String等, 所有的java类都要继承java.lang.Object类,下面不再赘述),直接委托其父加载器(SystemClassLoader)执行,这也是JVM类加载器的默认行为,由此第三方代码可以正常使用这些类;\n[0022] 2、对于不允许使用的本地模块中的类(如java.net.*和java.io.*等),自定义类加载器将直接抛出ClassNotFound异常;\n[0023] 3、需要访问外部资源的业务逻辑封装于单独的功能类中(下文称为Function类),自定义类加载器将直接由其父加载器加载Function类,由此Function类中再加载使用其它类时(如java.net.*等限制第三方代码使用的类)将直接使用父加载器,从而安全地绕过自定义类加载器的限制。\n[0024] 如此便可以实现第三方代码本身只能使用允许的类,可以轻易地断绝其访问外部资源(此处指所有不允许访问的资源包含虚拟机自身内存等)的途径,同时可以通过Function类提供的高级接口以可控的方式访问外部资源。\n[0025] 通常JVM提供的非访问外部资源的类可以由第三方代码安全调用,如java.lang.String以及java.math模块中的等大部分的类都是如此。对待这些类的加载,根据本发明的一个是实施例,自定义的类加载器MyClassLoader的行为即是JVM类加载器的默认行为,即双亲代理模式(即,优先委托自己的父加载器加载,父加载器不能加载时才自己加载。)。\n而对于java.io、java.net以及java.thread等模块中的类,自定义类加载器将会打破JVM的默认行为,从而拒绝加载这些类;自定义类加载器正常(委托其父加载器)加载Function类后,Function类便属于自定义类加载器的父加载器,所以Function类中的类加载将由自定义类加载器的父加载器负责,从而可以在Function中实现访问外部资源实现业务逻辑,Function代码由功能提供者实现,是可控的,而第三方代码只能通过这一条途径来访问外部资源,因此也是可控的。\n[0026] 自定义类加载器中的允许或不允许加载的类列表可以是预置的,所有的第三方类代码使用相同的配置;也可以是加载不同的第三方类代码时现读取的,每个类有不同的权限,由此在JVM中实现动态的代码权限控制。\n[0027] 在JVM中,通过类加载器和类名才能确定一个类,对于不同的第三方代码,都创建一个新的自定义类加载器实例来加载。由于第三方代码加载时需要不同的类加载器,所以第三方代码之间无法相互访问,从而实现了不同第三方代码之间的隔离。当所执行的第三方代码之间不需要隔离时(如是同一个用户的代码),则可以使用同一个类加载器加载,从而节省系统资源。\n[0028] 上述自定义类加载器通常可以通过重载ClassLoader类的findClass和loadClass方法即可实现,此为Java中的标准方法,本发明中不再赘述。\n[0029] 为使本发明的目的、技术方案及优点更加清楚明白,以下结合附图描述本发明的优选实施例,对本发明进一步详细说明。\n[0030] 如图1所示,本发明中自定义类加载器加载一个类包括如下步骤:其中,在该类的实例创建时已经获得了哪些类可加载而哪些类不可加载的信息,在图1中已经略去):\n[0031] 步骤1:开始执行;\n[0032] 步骤2:判断是否允许加载该类;如果允许加载该类,则进入步骤3,否则抛出ClassNotFound异常;\n[0033] 步骤3:判断加载的类是否是要限制使用的第三方类,如果是,则进入步骤4;如果不是,则进入步骤5;\n[0034] 步骤4:从字节码直接加载第三方类;\n[0035] 步骤5:委托父加载器加载第三方类;\n[0036] 步骤6:结束加载过程。\n[0037] 图2给出了实现本发明的结构示意图。\n[0038] 图2虚线框中为第三方代码运行环境,该环境运行在JVM中。其中包括第三方类代码本身和访问外部资源的业务逻辑封装类。\n[0039] 第三方类代码需要通过自定义类加载器才能被系统类加载器所加载,而访问外部资源的业务逻辑封装类则直接由系统类加载器加载。\n[0040] 其中,第三方类代码在未加载到JVM前是文本形式的代码,而加载到JVM中之后是一个类。。\n[0041] 实施例1\n[0042] 该实施例中需要加载的第三方类是ThirdExample。第三方类ThirdExample的字节码存在ThirdExample.class文件中,只允许直接使用java.lang.String类和默认的java.lang.Object类。而ThirdExample类只允许直接使用java.lang.String类的信息则存放在ThirdExampleAccess.txt这个文本文件中。在ThirdExample类中需要访问外部资源/tmp/example.db文件。该功能通过类example.FileAccessWrapper提供的公共方法(read和write,即读写功能)实现,而example.FileAccessWrapper是系统提供者提供的访问外部资源的封装类,该封装类根据系统的安全需求以及业务逻辑编写。在本例中example.FileAccessWrapper通过使用java.io.*等在ThirdExample中不能使用的类来实现文件操作,同时该类只能访问/tmp/example.db文件,从而防止了ThirdExample对其它资源的访问。\n[0043] 其中ThirdExampleAccess.txt文件的内容描述相应第三方代码可以加载的类,形式可以根据需求进行选择,如其中记录可以加载的类,或只记录不可以加载的类,或两者都记录等等。\n[0044] 通过ThirdExample.class可以确定其对应的权限文件的位置,如本例中可以通过文件名来找到ThirdExampleAccess.txt文件。ThirdExample类由自定义的类加载器MyClassLoader加载,本例中MyClassLoader的工作流程如下:\n[0045] 1、创建MyClassLoader,以当前线程的加载器作为其父加载器;\n[0046] 2、若加载ThirdExample类,则从ThirdExample.class中读取类字节码,然后加载;同时读取对应的ThirdExampleAccess.txt,确定ThirdExample可使用类的列表(或不可加载类的列表);3、加载(都是从类ThirdExample中)其它类时,若ThirdExampleAccess.txt中允许加载,则委托其父加载器加载,否则抛出ClassNotFound异常;\n[0047] 本例中只有java.lang.String和example.FileAccessWrapper可以加 载,在ThirdExample所有加载其它类的操作均会抛出ClassNotFound异常,从而使得ThridExample没有途径直接访问外部资源,example.FileAccessWrapper提供了访问外部资源途径的同时也隐藏了相关细节。\n[0048] 4、当ThirdExample类执行完毕后,MyClassLoader便不再使用(可被回收)。此外,根据本实施例,可以根据需要同时创建多个MyClassLoader以执行多份ThirdExample代码,这些MyClassLoader之间的执行过程互不影响。\n[0049] 实施例2\n[0050] 同上例,只是控制第三方类中可访问的资源不同。第三方类代码ThirdExample.class(存在文件中)允许直接使用除java.net.*以外的所有类,此信息放在ThirdExampleAccess.txt这个文本文件。外部需要通过网络访问TCP的80端口。该功能通过类example.NetAccessWrapper提供的公共方法(open、send、recieve和close,即打开、发送、接收和关闭功能)实现,example.NetAccessWrapper隐藏为网络访问的细节(如协议、端口和底层实现等)。example. NetAccessWrapper是系统提供者提供的访问外部资源的封装类,根据系统的安全需求以及业务逻辑编写。在本例中example. NetAccessWrapper通过使用java.net.*等在ThirdExample中不能使用的类来实现文件操作,同时该类只能访问TCP的80端口,从而防止了ThirdExample对其它网络资源的访问。\n[0051] 自定义的类加载器MyClassLoader工作流程如下:\n[0052] 1、创建MyClassLoader,以当前线程的加载器作为其父加载器;\n[0053] 2、若加载ThirdExample类,则从ThirdExample.class中读取类字节码,然后加载;同时读取对应的ThirdExampleAccess.txt,确定ThirdExample可使用类的列表(或不可加载类的列表);\n[0054] 3、加载(都是从类ThirdExample中加载)其它类时,若ThirdExampleAccess.txt中允许加载,则委托其父加载器加载,否则抛出ClassNotFound异常;本例中除java.net.*以外的所有类都可以加载,在ThirdExample所有加载任何java.net.*类的操作均会抛出ClassNotFound异常,从而使得ThridExample没有途径直接访问网络,example.NetAccessWrapper提供了访问外部资源途径的同时也隐藏了相关细节。\n[0055] 4、当ThirdExample类执行完毕后,MyClassLoader便不再使用(可被回收)。此外,根据本实施例,可以根据需要同时创建多个MyClassLoader以执行多份ThirdExample代码,这些MyClassLoader之间的执行过程互不影响。\n[0056] 实施例3\n[0057] 此外,根据本发明的一个具体实施方式,除了上述两个具体实施例中通过读取ThirdExampleAccess.txt,从而确定ThirdExample可使用类的列表(或不可加载类的列表)的方式之外,本领域的技术人员完全可以采用其它的方式来确定所述第三方类所允许访问的类和/或所不允许访问的类的信息,其中一种具体的方式就是将所述信息存放在数据库中,或所述信息直接写入在程序代码中。这种变化对于本领域技术人员而言是容易实现的,其相应的后续步骤与上述实施例1、2的后续步骤类似,不再赘述。\n[0058] 以上所述仅为本发明的较佳实施例而已,并非用于限定本发明的保护范围。凡在本发明的精神和原则之内,所作的任何修改、等同替换以及改进等,均应包含在本发明的保护范围之内。
法律信息
- 2023-01-13
专利权人的姓名或者名称、地址的变更
专利权人由北京深思数盾科技股份有限公司变更为北京深盾科技股份有限公司
地址由100193 北京市海淀区西北旺东路10号院东区5号楼5层510变更为100193 北京市海淀区西北旺东路10号院东区5号楼5层510
- 2016-11-16
专利权人的姓名或者名称、地址的变更
专利权人由北京深思数盾科技有限公司变更为北京深思数盾科技股份有限公司
地址由100872 北京市海淀区中关村大街甲59号文化大厦1706变更为100193 北京市海淀区西北旺东路10号院东区5号楼5层510
- 2015-08-19
- 2015-08-12
专利申请权的转移
登记生效日: 2015.07.22
申请人由北京深思洛克软件技术股份有限公司变更为北京深思数盾科技有限公司
地址由100084 北京市海淀区中关村南大街甲6号铸诚大厦1906变更为100872 北京市海淀区中关村大街甲59号文化大厦1706
- 2013-03-13
实质审查的生效
IPC(主分类): G06F 21/51
专利申请号: 201210344765.8
申请日: 2012.09.18
- 2013-01-30
引用专利(该专利引用了哪些专利)
序号 | 公开(公告)号 | 公开(公告)日 | 申请日 | 专利名称 | 申请人 |
1
| |
2010-06-30
|
2008-12-26
| | |
2
| |
2008-01-16
|
2007-08-31
| | |
3
| |
2010-12-22
|
2009-12-01
| | |
被引用专利(该专利被哪些专利引用)
序号 | 公开(公告)号 | 公开(公告)日 | 申请日 | 专利名称 | 申请人 | 该专利没有被任何外部专利所引用! |