天天看點

深入Java虛拟機(3)——安全

版權聲明:本文為部落客原創文章,轉載注明出處http://blog.csdn.net/u013142781

1.0版本的基本沙箱 

1.1版本的代碼簽名和認證 

1.2版本的細粒度通路控制

java安全模型側重于保護終端使用者免受從網絡下載下傳的、來自不可靠來源的、惡意程式(以及善意程式中的bug)的侵犯。為此,java從jdk 1.0開始實作了一套沙箱環境(基本沙箱),沙箱對不可靠的活動進行了限制,程式可以在沙箱的安全邊界内做任何事,但不能進行任何跨越這些邊界的舉動。

但由于最初的沙箱限制過于嚴格,善意(但不可靠)的代碼常常無法進行有效工作。在版本1.1中,得到了改進,引入了基于代碼簽名和認證的信任模式。使得接收終端系統哦就能夠可以确認一系列class檔案(在一個jar檔案中)已經由某一實體進行了數字簽名(有效,可被信賴),并且在簽名過後,這些class檔案沒有改動,這使得終端使用者和系統管理者減少了對某些代碼在沙箱中的限制,但這些代碼必須已由可信任團體進行數字簽名。

雖然版本1.1中釋出的安全api包含了對認證的支援,但是實際上,除了提供完全信任和完全不信任政策(換句話說,代碼要麼完全被信任,要麼我完全不被信任)以外,沒有提供其他實際幫助。後面的1.2版本提供的api可以幫助建立細粒度的安全政策。

下面詳細看看基本沙箱、代碼簽名和認證、細粒度通路控制是如何實作的。

java沙箱 安全建立在 java 運作時環境的三個基本方面的基礎上:bytecode verifier(位元組碼驗證器)、security manager(安全管理器)以及 classloader(類裝入器)。

bytecode verifier:它確定所下載下傳的代碼被恰當地格式化,位元組碼(“java 虛拟機”指令)沒有違反這種語言或虛拟機的安全限制(無非法資料轉換),沒有執行指針尋址,内部堆棧不能溢出或下溢,以及位元組碼指令将擁有正确的類型參數。

security manager:它在嘗試執行檔案 i/o 和網絡 i/o、建立新的classloader、操作線程或線程組、啟動底層平台(作業系統)上的程序、終止“java 虛拟機”、将非 java 庫(本機代碼)裝入到 jvm、完成某種類型的視窗系統操作以及将某種類型的類裝入到 jvm 中時發起運作時通路控制。

classloader:java程式(class檔案)并不是本地的可執行程式。當運作java程式時,首先運作jvm(java虛拟機),然後再把java class加載到jvm裡頭運作,負責加載java class的這部分就叫做class loader。當運作一個程式的時候,jvm啟動,運作bootstrapclassloader,該classloader加載java核心api(extclassloader和appclassloader也在此時被加載),然後調用extclassloader加載擴充api,最後appclassloader加載classpath目錄下定義的class,這就是一個程式最基本的加載流程。

java1.1的java.security包中引入的認證政策,認證能幫助使用者通過實作一個沙箱來建立多種安全政策。認證可以使使用者相信由某些團體擔保的class檔案具有高度的可信度,并且這些class檔案沒有在到達java虛拟機之前的網絡傳輸中被改變。這樣,就可以簡化沙箱對被認證代碼的限制,針對由不同團體簽名的代碼建立不同的安全限制。

要對一段代碼進行擔保簽名,首先要生成一個公鑰/私鑰對。使用者要公開公鑰,保管私鑰。之後将要簽名的class檔案和其他檔案放在一個jar檔案中,然後用諸如sdk中的jarsigner 工具對整個jar檔案簽名。這個簽名工具将首先通過單項散列計算,對jar檔案産生一個散列,然後用私鑰對這個散列簽名,并在jar檔案的末尾加上這個簽名,進而完成你對這個jar檔案的數字簽名。

數字簽名的散列計算中大量輸入的是組成jar檔案内容的位元組流,産生的是不能包含所有輸入資訊的少量資料。這個計算是單向的:從大到小,從輸入到散列。為了加強安全性,要用私鑰進行加密。因為私鑰加密是一個非常費時的過程,我們隻對散列進行私鑰的加密。公鑰/私鑰對具有如下特點:在僅給出公鑰的情況下時,想要産生私鑰是非常困難的,而且任何用私鑰加密的代碼都可以用配對的公鑰才能解密。因為不同的輸入可能産生相同的散列,而産生相同散列的機率主要依賴于散列的大小。在實際情況下,散列主要采用64位或128位,這樣的長度要想從不同的輸入中産生一個相同的散列的計算是不可行的。之後将這個加密後的散列值加到同一個jar檔案中,這個jar檔案還包含了你最初産生這個散列的檔案。

接受者必須用公鑰對簽名散列進行解密,通過得到的結果和從jar檔案計算得到的散列是否相同,可以驗證一個已經簽名的jar檔案。如果得到的散列值和解密的散列值比對,則表明了接受者收到的jar檔案确實被發送者所擔保,并且傳輸過程中沒有被修改,這個檔案安全性是有保障的。這樣,就可以将這個jar檔案放入安全級别不很嚴格的一般沙箱裡,這個沙箱信任發送者的簽名。

版本1.2的安全體系結構的主要目标之一就是使建立(以簽名代碼為基礎的)細粒度的通路控制政策的過程更為簡單且更少出錯。版本1.2的安全體系結構中,對應于整個java應用程式的一個通路控制政策是由抽象類java.security.policy的一個子類的單個執行個體所表示的。

安全政策是一個從描述運作代碼的屬性集合到這段代碼所擁有的權限的映射。在版本1.2的安全體系結構中,描述運作代碼的屬性被總稱為代碼來源。一個代碼來源是由一個java.security.codesource對象表示的,這個對象中包含了一個java.net.url,它表示代碼庫和代表了簽名者的零個或多個證書對象的數組。證書對象是抽象類java.security.cert.certificate的子類的一個執行個體,一個certificate對象抽象表示了從一個人到一個公鑰的綁定,以及另一個為這個綁定作擔保的人(以前提過的證書機構)。codesource對象包含了一個certificate對象的數組,因為同一段代碼可以被多個團體簽名(擔保)。這個簽名通常是從jar檔案中獲得的。

權限是用抽象類java.security.permission的一個子類的執行個體表示的。一個permission對象有三個屬性:類型、名字和可選的操作。

在policy對象中,每一個codesource是和一個或多個permission對象相關聯的。和一個codesource相關聯的permission對象被封裝在java.security.permissioncollection的一個子類執行個體中。

參考資料: 

《深入java虛拟機 第二版》 

<a href="http://www.1k2k.net/ligongkeji/2012/0507/52776.html">http://www.1k2k.net/ligongkeji/2012/0507/52776.html</a>