專利名稱:一種在Java虛擬機中安全運行第三方代碼的方法
技術領域:
本發(fā)明涉及信息安全領域,特別涉及一種安全運行不可控的第三方代碼的方法。
背景技術:
軟件或服務器往往需要允許用戶執(zhí)行自定義的代碼以實現(xiàn)高度的可定制性或安全性。但是由于第三方編寫的代碼的不可控性,限制其運行環(huán)境以保護服務器資源或上層軟件的正常運行就成了一個很重要的問題。JVM是Java Virtual Machine (Java虛擬機)的縮寫,JVM是一種用于計算設備的規(guī)范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。JVM屏蔽了與具體操作系統(tǒng)平臺相關的信息,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行。JVM在執(zhí)行字節(jié)碼·時,實際上最終還是把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行。在JVM中使用一個類時,該類的加載過程是唯一可以在外部進行干預的,這可以通過JVM提供的自定義類加載器來實現(xiàn)。通常JVM中引入自定義類加載器的主要目的是實現(xiàn)代碼的熱部署,如OSGi系統(tǒng)等。OSGi (Open Service Gateway Initiative)技術是面向Java的動態(tài)模型系統(tǒng)。OSGi服務平臺向Java提供服務,這些服務使Java成為軟件集成和軟件開發(fā)的首選環(huán)境。OSGi技術提供允許應用程序使用精煉、可重用和可協(xié)作的組件構建的標準化原語。這些組件能夠組裝進一個應用和部署中。JVM虛擬機提供的安全性主要通過虛擬機的安全策略文件實現(xiàn),通過安全策略文件控制JVM中類對資源的訪問(如文件系統(tǒng)和網(wǎng)絡資源等)。但是在實際應用中,往往需要控制第三方代碼本身不能直接訪問一些外部資源(如文件、網(wǎng)絡和一些本地模塊的加載等),但是可以通過調用本地提供的方法來訪問,而且JVM同時運行多個不同的第三方代碼時還要實現(xiàn)代碼間的相互隔離,這時只通過在JVM啟動時靜態(tài)地提供一個安全策略文件很難實現(xiàn)。
發(fā)明內容
有鑒于此,本發(fā)明提供了一種在JVM上安全運行第三方代碼的方法,利用JVM提供的自定義類加載器的技術來控制第三方代碼的本地模塊和類的加載,只允許第三方代碼加載和使用系統(tǒng)提供的已封裝好業(yè)務邏輯的類,第三方代碼對外部資源的訪問只能通過上述系統(tǒng)提供的已封裝好的業(yè)務邏輯類的接口執(zhí)行,第三方代碼本身不能直接訪問外部資源,從而實現(xiàn)安全訪問外部資源。根據(jù)本發(fā)明,提供一種在Java虛擬機中安全運行第三方類的方法,該方法包括 創(chuàng)建自定義加載器,所述自定義加載器的父加載器為Java虛擬機當前線程的類加載
器;
通過所述自定義加載器來加載第三方類,由所述自定義加載器判斷是否允許所述第三方類加載特定的系統(tǒng)類;如果允許,則所述自定義加載器委托其父加載器加載所述系統(tǒng)類;
若不允許,則拋出異常,從而控制所述第三方類中所能使用的類。根據(jù)本發(fā)明的一個方面,根據(jù)需要,能夠同時創(chuàng)建多個所述自定義加載器以執(zhí)行多份所述第三方類。根據(jù)本發(fā)明的一個方面 ,關于所述第三方類所允許訪問的類和/或所不允許訪問的類的信息存放在所述自定義類加載器能夠找到的存放位置。根據(jù)本發(fā)明的一個方面,所述信息存放在特定文件中,或所述信息存放在數(shù)據(jù)庫中,或所述信息直接寫入在程序代碼中。根據(jù)本發(fā)明的一個方面,所述自定義類加載器加載所述第三方類時,確定所述第三方類可使用和/或不可使用的類。根據(jù)本發(fā)明的一個方面,如果所述自定義加載器判斷出所述第三方類加載不允許加載的類時,拋出異常。根據(jù)本發(fā)明的一個方面,分別采用不同的加載器來分別加載所述第三方類以防止惡意訪問。
圖I為按照本發(fā)明的一種在JVM上安全運行第三方代碼的方法的一優(yōu)選實施例的流程示意圖。圖2為圖I所示實施例中結構框圖。
具體實施例方式當JVM需要加載第三方代碼時,創(chuàng)建一個自定義的類加載器,其父加載器設置為JVM當前線程的默認類加載器(根據(jù)本發(fā)明的一個實施例,通常就是SystemClassLoader),通過自定義類加載器的一個實例來加載第三方代碼。在自定義類加載器中通過一個可使用類的列表(或不可使用類的列表)來控制第三方代碼中外部類的使用,自定義類加載器的功能如下
1、對于允許使用的本地模塊中的類(如java.lang. String等,所有的java類都要繼承java. lang. Object類,下面不再贅述),直接委托其父加載器(SystemClassLoader)執(zhí)行,這也是JVM類加載器的默認行為,由此第三方代碼可以正常使用這些類;
2、對于不允許使用的本地模塊中的類(如java.net. *和java. io. *等),自定義類加載器將直接拋出ClassNotFound異常;
3、需要訪問外部資源的業(yè)務邏輯封裝于單獨的功能類中(下文稱為Function類),自定義類加載器將直接由其父加載器加載Function類,由此Function類中再加載使用其它類時(如java. net. *等限制第三方代碼使用的類)將直接使用父加載器,從而安全地繞過自定義類加載器的限制。如此便可以實現(xiàn)第三方代碼本身只能使用允許的類,可以輕易地斷絕其訪問外部資源(此處指所有不允許訪問的資源包含虛擬機自身內存等)的途徑,同時可以通過Function類提供的高級接口以可控的方式訪問外部資源。通常JVM提供的非訪問外部資源的類可以由第三方代碼安全調用,如java. lang.String以及java. math模塊中的等大部分的類都是如此。對待這些類的加載,根據(jù)本發(fā)明的一個是實施例,自定義的類加載器MyClassLoader的行為即是JVM類加載器的默認行為,即雙親代理模式(即,優(yōu)先委托自己的父加載器加載,父加載器不能加載時才自己加載。)。而對于java. io、java. net以及java. thread等模塊中的類,自定義類加載器將會打破JVM的默認行為,從而拒絕加載這些類;自定義類加載器正常(委托其父加載器)加載Function類后,F(xiàn)unction類便屬于自定義類加載器的父加載器,所以Function類中的類加載將由自定義類加載器的父加載器負責,從而可以在Function中實現(xiàn)訪問外部資源實現(xiàn)業(yè)務邏輯,F(xiàn)unction代碼由功能提供者實現(xiàn),是可控的,而第三方代碼只能通過這一條途徑來訪問外部資源,因此也是可控的。自定義類加載器中的允許或不允許加載的類列表可以是預置的,所有的第三方類代碼使用相同的配置;也可以是加載不同的第三方類代碼時現(xiàn)讀取的,每個類有不同的權限,由此在JVM中實現(xiàn)動態(tài)的代碼權限控制。在JVM中,通過類加載器和類名才能確定一個類,對于不同的第三方代碼,都創(chuàng)建
一個新的自定義類加載器實例來加載。由于第三方代碼加載時需要不同的類加載器,所以第三方代碼之間無法相互訪問,從而實現(xiàn)了不同第三方代碼之間的隔離。當所執(zhí)行的第三方代碼之間不需要隔離時(如是同一個用戶的代碼),則可以使用同一個類加載器加載,從而節(jié)省系統(tǒng)資源。 上述自定義類加載器通??梢酝ㄟ^重載ClassLoader類的f indClass和IoadClass方法即可實現(xiàn),此為Java中的標準方法,本發(fā)明中不再贅述。
為使本發(fā)明的目的、技術方案及優(yōu)點更加清楚明白,以下結合附圖描述本發(fā)明的優(yōu)選實施例,對本發(fā)明進一步詳細說明。如圖I所示,本發(fā)明中自定義類加載器加載一個類包括如下步驟其中,在該類的實例創(chuàng)建時已經獲得了哪些類可加載而哪些類不可加載的信息,在圖I中已經略去)
步驟I :開始執(zhí)行;
步驟2:判斷是否允許加載該類;如果允許加載該類,則進入步驟3,否則拋出ClassNotFound 異常;
步驟3 :判斷加載的類是否是要限制使用的第三方類,如果是,則進入步驟4 ;如果不是,則進入步驟5;
步驟4 :從字節(jié)碼直接加載第三方類;
步驟5 :委托父加載器加載第三方類;
步驟6:結束加載過程。圖2給出了實現(xiàn)本發(fā)明的結構示意圖。圖2虛線框中為第三方代碼運行環(huán)境,該環(huán)境運行在JVM中。其中包括第三方類代碼本身和訪問外部資源的業(yè)務邏輯封裝類。第三方類代碼需要通過自定義類加載器才能被系統(tǒng)類加載器所加載,而訪問外部資源的業(yè)務邏輯封裝類則直接由系統(tǒng)類加載器加載。其中,第三方類代碼在未加載到JVM前是文本形式的代碼,而加載到JVM中之后是
一個類。。
實施例I
該實施例中需要加載的第三方類是ThirdExample。第三方類ThirdExample的字節(jié)碼存在ThirdExample. class文件中,只允許直接使用java. lang. String類和默認的java.lang. Object類。而ThirdExample類只允許直接使用java. lang. String類的信息則存放在ThirdExampleAccess. txt這個文本文件中。在ThirdExample類中需要訪問外部資源/tmp/example, db文件。該功能通過類example. FileAccessffrapper提供的公共方法(read和write,即讀寫功能)實現(xiàn),而example. FileAccessffrapper是系統(tǒng)提供者提供的訪問外部資源的封裝類,該封裝類根據(jù)系統(tǒng)的安全需求以及業(yè)務邏輯編寫。在本例中example.FileAccessWrapper通過使用java. io. *等在ThirdExample中不能使用的類來實現(xiàn)文件操作,同時該類只能訪問/tmp/example. db文件,從而防止了 ThirdExample對其它資源的訪問。其中ThirdExampleAccess. txt文件的內容描述相應第三方代碼可以加載的類, 形式可以根據(jù)需求進行選擇,如其中記錄可以加載的類,或只記錄不可以加載的類,或兩者者[H己錄等等。通過ThirdExample. class可以確定其對應的權限文件的位置,如本例中可以通過文件名來找到ThirdExampleAccess. txt文件。ThirdExample類由自定義的類加載器MyClassLoader加載,本例中MyClassLoader的工作流程如下
1、創(chuàng)建MyClassLoader,以當前線程的加載器作為其父加載器;
2、若加載ThirdExample類,則從ThirdExample.class中讀取類字節(jié)碼,然后加載;同時讀取對應的ThirdExampleAccess. txt,確定ThirdExample可使用類的列表(或不可加載類的列表);3、加載(都是從類ThirdExample中)其它類時,若ThirdExampleAccess. txt中允許加載,則委托其父加載器加載,否則拋出ClassNotFound異常;
本例中只有 java. lang. String 和 example. FileAccessWrapper 可以加載,在ThirdExample所有加載其它類的操作均會拋出ClassNotFound異常,從而使得ThridExample沒有途徑直接訪問外部資源,example. FileAccessffrapper提供了訪問外部資源途徑的同時也隱藏了相關細節(jié)。4、當ThirdExample類執(zhí)行完畢后,MyClassLoader便不再使用(可被回收)。此外,根據(jù)本實施例,可以根據(jù)需要同時創(chuàng)建多個MyClassLoader以執(zhí)行多份ThirdExample代碼,這些MyClassLoader之間的執(zhí)行過程互不影響。
實施例2
同上例,只是控制第三方類中可訪問的資源不同。第三方類代碼ThirdExample.class (存在文件中)允許直接使用除java. net. *以外的所有類,此信息放在ThirdExampleAccess. txt這個文本文件。外部需要通過網(wǎng)絡訪問TCP的80端口。該功能通過類 example. NetAccessffrapper 提供的公共方法(open、send、recieve 和 close,即打開、發(fā)送、接收和關閉功能)實現(xiàn),example. NetAccessffrapper隱藏為網(wǎng)絡訪問的細節(jié)(如協(xié)議、端口和底層實現(xiàn)等)。example. NetAccessffrapper是系統(tǒng)提供者提供的訪問外部資源的封裝類,根據(jù)系統(tǒng)的安全需求以及業(yè)務邏輯編寫。在本例中example. NetAccessffrapper通過使用java. net. *等在ThirdExample中不能使用的類來實現(xiàn)文件操作,同時該類只能訪問TCP的80端口,從而防止了 ThirdExample對其它網(wǎng)絡資源的訪問。自定義的類加載器MyClassLoader工作流程如下
1、創(chuàng)建MyClassLoader,以當前線程的加載器作為其父加載器;
2、若加載ThirdExample類,則從ThirdExample. class中讀取類字節(jié)碼,然后加載;同時讀取對應的ThirdExampleAccess. txt,確定ThirdExample可使用類的列表(或不可加載類的列表);
3、加載(都是從類ThirdExample中加載)其它類時,若ThirdExampleAccess.txt中允許加載,貝U委托其父加載器加載,否則拋出ClassNotFound異常;本例中除java.net. *以外的所有類都可以加載,在ThirdExample所有加載任何java. net. *類的操作均會拋出ClassNotFound異常,從而使得ThridExample沒有途徑直接訪問網(wǎng)絡,example.NetAccessffrapper提供了訪問外部資源途徑的同時也隱藏了相關細節(jié)。 4、當ThirdExample類執(zhí)行完畢后,MyClassLoader便不再使用(可被回收)。此夕卜,根據(jù)本實施例,可以根據(jù)需要同時創(chuàng)建多個MyClassLoader以執(zhí)行多份ThirdExample代碼,這些MyClassLoader之間的執(zhí)行過程互不影響。
實施例3
此外,根據(jù)本發(fā)明的一個具體實施方式
,除了上述兩個具體實施例中通過讀取ThirdExampleAccess. txt,從而確定ThirdExample可使用類的列表(或不可加載類的列表)的方式之外,本領域的技術人員完全可以采用其它的方式來確定所述第三方類所允許訪問的類和/或所不允許訪問的類的信息,其中一種具體的方式就是將所述信息存放在數(shù)據(jù)庫中,或所述信息直接寫入在程序代碼中。這種變化對于本領域技術人員而言是容易實現(xiàn)的,其相應的后續(xù)步驟與上述實施例1、2的后續(xù)步驟類似,不再贅述。
以上所述僅為本發(fā)明的較佳實施例而已,并非用于限定本發(fā)明的保護范圍。凡在本發(fā)明的精神和原則之內,所作的任何修改、等同替換以及改進等,均應包含在本發(fā)明的保護范圍之內。
權利要求
1.一種在Java虛擬機中安全運行第三方類的方法,其特征在于,該方法包括 創(chuàng)建自定義加載器,所述自定義加載器的父加載器為Java虛擬機當前線程的類加載器; 通過所述自定義加載器來加載第三方類,由所述自定義加載器判斷是否允許所述第三方類加載特定的系統(tǒng)類; 如果允許,則所述自定義加載器委托其父加載器加載所述系統(tǒng)類; 若不允許,則拋出異常,從而控制所述第三方類中所能使用的類。
2.根據(jù)權利要求I所述的方法,其特征在于,根據(jù)需要,能夠同時創(chuàng)建多個所述自定義加載器以執(zhí)行多份所述第三方類。
3.根據(jù)權利要求I所述的方法,其特征在于,關于所述第三方類所允許訪問的類和/或所 不允許訪問的類的信息存放在所述自定義類加載器能夠找到的存放位置。
4.根據(jù)權利要求3所述的方法,其特征在于,所述信息存放在特定文件中,或所述信息存放在數(shù)據(jù)庫中,或所述信息直接寫入在程序代碼中。
5.根據(jù)權利要求2所述的方法,其特征在于,所述自定義類加載器加載所述第三方類時,確定所述第三方類可使用和/或不可使用的類。
6.根據(jù)權利要求1-5所述的方法,其特征在于,如果所述自定義加載器判斷出所述第三方類加載不允許加載的類時,拋出異常。
7.根據(jù)權利要求2所述的方法,其特征在于,分別采用不同的加載器來分別加載所述第三方類以防止惡意訪問。
全文摘要
本發(fā)明公開了一種利用JVM提供的自定義類加載器的技術實現(xiàn)安全運行不可控的第三方代碼的方法。通過控制第三方代碼中可以使用的本地模塊和類,可以有效限制其對外部資源的訪問,同時也可以隔離多個同時運行的第三方代碼。本發(fā)明也提供了在第三方代碼中以可控的方式透明訪問本地資源的方法。
文檔編號G06F9/445GK102902911SQ20121034476
公開日2013年1月30日 申請日期2012年9月18日 優(yōu)先權日2012年9月18日
發(fā)明者不公告發(fā)明人 申請人:北京深思洛克軟件技術股份有限公司