網絡移動性和平臺無關性略過。。。看看java如何實現安全性
Java通過提供一個”安全沙箱“來保證從網絡或者其他不信任的地方下載并運行的程序不會破壞本地數據,為了確保沙箱是可靠的,java安全模型對體系結構的各方面都進行了考慮。組成java沙箱的基本組件如下:
- 類裝載器結構
- class文件檢驗器
- 內置于Java虛擬機(及語言)的安全特性
- 安全管理器及Java API
Java的沙箱安全模型,最重要的優點之一就是這些組件中的類裝載器和安全管理器是可以由用戶定制的。
1、類裝載器體系結構
java沙箱中,類裝載器體系結構是第一道防線,類裝載器體系結構在三個方面對Java的沙箱起作用:
- 它防止惡意代碼去干涉善意的代碼。-------通過為由不同的類裝載器裝入的類提供不同的命名空間來實現的,這個命名空間由Java虛擬機維護
- 它守護了被信任的類庫的邊界。--------通過分別使用不同的類裝載器裝載可靠的包和不可靠的包來實現,參見例1和例2的加深理解。
- 它將代碼歸入了某類(稱為保護域),該類確定了代碼可以進行哪些操作。
例1:如果某個惡意的類可以成功欺騙Java虛擬機,使Java虛擬機相信它是一個來自Java API的可信任類,那么,這個惡意的類就可以突破沙箱的阻隔了,讓我們看看java如何阻止這種情況的發生。
Java的類裝載器結構是一個以啟動類裝載器為根的委派鏈,子 類裝載器在裝載一個類時首先會請求其雙親類裝載器來裝載,如果雙親裝載器能夠裝載成功,則直接使用該類型,只有所有雙親類裝載器都裝載失敗的時候,才會根據自定義的方法去裝載該類型,這中工作方式被稱作”雙親委派模式“。
在這種模式下,如果一個自定義的網絡類裝載器試圖從網絡上下載一個和Java API中某個類型同名的類型,如java.lang.Integer時,它將不能成功,因為通過層層委派,這個類型會被啟動類裝載器裝載,而網絡類裝載器將直接使用正確的java.lang.Integer,而沒有機會從網絡上下載并裝載這個惡意的java.lang.Integer。
例2:如果自定義的網絡類裝載器不像例1一樣去替換一個被信任的類,而是在被信任的包中插入一個全新的類型,比如,一個java.lang.Virus的時候,將會發生什么?
通過層層委派,網絡類裝載器最終會正確裝載這個名為java.lang.Virus的類,暗示了這個類是Java API的一部分,因此,它可以訪問java.lang包中被信任類的特殊訪問權限(protected),然而,這個情況不會發生,因為java虛擬機只把彼此訪問的特殊權限授予由同一個類裝載器裝載到同一個包中的類型,即只有同一個”運行時包“的類之間才有特殊訪問權限,而java.lang.Virus和java.lang中其他被信任的類分別有網絡類裝載器和啟動類裝載器裝載,它們不屬于同一個運行時包。
和類裝載器一起,class文件檢驗器包裝裝載的class文件內容有正確的內部結構,并且這些class文件相互間協調一致,class文件檢驗器實現的安全目標之一就是程序的健壯性,它必須保證一個class的裝載不會導致虛擬機的崩潰。
class文件檢驗器要進行四趟獨立的掃描來完成它的操作。第一趟掃描是在類被裝載時進行的,在這次掃描中,class文件檢驗器檢查這個class文件的內部結構,以保證它可以被安全的編譯;第二趟和第三趟掃描是在連接過程中進行的,在這兩次掃描中,class文件檢驗器確認類型數據遵從Java編程語言的語義,包括檢驗它所包含的所有字節碼的完整性;第四趟掃描是在進行動態連接的過程中解析符號引用時進行的,在這次掃描中,class文件檢驗器確認被引用的類、字段以及方法確實存在。
第一趟掃描: class文件的結構檢查
class文件檢驗器會檢查每一段被當作類型導入的字節序列是否符合java class文件的基本結構,比如是否是以魔數0xCAFEBABE開頭,確認class文件中聲明的主版本號和次版本號是否在這個java虛擬機的支持范圍內,必須確認這個文件沒有被刪節或者附加一些字節(通過每個定義長度的地方來確定總體長度)。第一趟掃描的主要目的是保證這個字節序列正確的定義了一個類型,它必須遵從java class文件的固定格式,這樣它才能被編譯成在方法區中的(基于實現的)內部數據結構。第二、三、四趟掃描不是在符合class文件的二進制數據上進行的,而是在方法區中、由實現決定的數據結構上進行的。
第二趟掃描: 類型數據的語義檢查
這次檢查,class文件檢驗器不需要查看字節碼,也不需要查看和裝載任何其他類型。在這趟掃描中,檢驗器查看每個組成部分,確認它們是否是其所屬類型的實例,它們結構是否正確。比如,方法描述符(它的返回類型,以及參數的類型和個數)在class文件中被存儲為一個字符串,這個字符串必須符合特定的上下文無關文法。另外,還會檢查這個類本身是否符合特定的條件,它們是由java編程語言規定的。比如,除Object外,所有類都必須要有一個超類,final的類不能被子類化,final方法也沒有被覆蓋,檢查常量池中的條目是合法的,而且常量池的所有索引必須指向正確類型的常量池條目。
第三趟掃描: 字節碼驗證
字節碼流代表了java的方法,它是由被稱為操作碼的單字節指令組成的序列,每一個操作碼后都跟著一個或多個操作數。執行字節碼時,依次執行操作碼,這就在java虛擬機內構成了執行的線程,每一個線程被授予自己的java棧,這個棧是由不同的棧幀構成的,每一個方法調用將獲得一個自己的棧幀----棧幀其實就是一個內存片段,其中存儲著局部變量和計算的中間結果,用于存儲中間結果的部分被稱為操作數棧。
字節碼檢驗器要進行大量的檢查,以確保采用任何路徑在字節碼流中都得到一個確定的操作碼,確保操作數棧總是包含正確的數值以及正確的類型。它必須保證局部變量在賦予合適的值以前不能被訪問,而且類的字段中必須總是被賦予正確類型的值,類的方法被調用時總是傳遞正確數值和類型的參數。字節碼檢驗器還必須保證每個操作碼都是合法的,即都有合法的操作數,以及對每一個操作碼,合適類型的數值位于局部變量中或是在操作數棧中。這些僅僅是字節碼檢驗器所做的大量檢驗工作中的一小部分,在整個檢驗過程通過后,它就能保證這個字節碼流可以被java虛擬機安全的執行。
第四趟掃描: 符合引用的驗證
在動態連接過程中,如果包含在一個class文件中的符號引用被解析時,class文件檢驗器進行第四趟掃描。在這趟掃描中,java虛擬機將追蹤那些引用-----從被驗證的class文件到被引用的class文件,以確保這個引用是正確的。這次掃描可能要裝載新的類。考慮到虛擬機實現上的差別,第四趟掃描可能緊隨第三趟掃描發生,也有可能在第三趟掃描之后很久,當字節碼被執行時才執行。
動態連接是一個將符號引用解析為直接引用的過程。當java虛擬機執行字節碼時,如果它遇到一個操作碼,這個操作碼第一次使用一個指向另一個類的符號引用,那么虛擬機就必須解析這個符號引用。在解析時,虛擬機執行兩個基本任務:
1)查找被引用的類(如果必要的話就裝載它)
2)將符號引用替換為直接引用,例如指向一個類、字段或方法的指針或偏移量
虛擬機必須記住這個直接引用,這樣當它以后再次遇到同樣的引用時,就可以直接使用,而不需要重新解析該符號引用了。
二進制兼容性規則
為了能方便的修改類庫的代碼,java編程語言被設計成允許對一個類做多種修改,但并不要求對依賴于它的那些類進行重編譯。java語言規范中列出了用戶可以做的多種改動,這些改動稱為二進制兼容性規則。這些規則明確地定義了:在一個類中,哪些可以被修改、增加和刪除,而并不破壞這個被修改的類與依賴于它的那些事先已經存在的類之間的二進制兼容性。
3、java虛擬機中內置的安全特性
除了四趟掃描之外,java虛擬機在執行字節碼時還進行其他一些內置的安全機制的操作,這些機制大多數是java的類型安全的基礎,它們作為java編程語言保證java程序的健壯性,同樣,它們也是java虛擬機的特性:
- 類型安全的引用轉換
- 結構化的內存訪問(無指針算法)
- 自動垃圾收集(不必顯式地釋放被分配的內存)
- 數組邊界檢查
- 空引用檢查
4、安全管理器和Java API
java安全模型的前三個部分共同達到了一個目的:保持java虛擬機的實例和它正在運行的應用程序的內部完整性,使得它們不被下載的惡意或有漏洞的代碼侵犯。相反,java安全模型的第四個組成部分---安全管理器---則用于保護虛擬機外部資源不被虛擬機內運行的惡意或有漏洞的代碼侵犯。這個安全管理器是一個單獨的對象,在運行的java虛擬機中,它在訪問控制---對于外部資源的訪問控制---中起中樞作用。
安全管理器定義了沙箱的外部邊界,并且它是可以定制的。
安全管理器中需要了解如下一些概念和類:
- 默認安全管理器:java.lang.SecurityManager
- 代碼簽名和認證
- 策略:java.security.Policy
- 權限:java.security.Permission
- 策略文件
- 保護域:CodeSource,PersimissionCollection,ProtectionDomain
- 訪問控制器:java.security.AccessController
這部分內容太多,只能帶過了。
Java安全模型的不足
Java安全模型尚不能解決如下問題:
- 不斷分配內存,直到內存耗盡
- 不斷生成線程導致每件事都慢的不可忍受
以上兩中類型的攻擊被稱作拒絕服務攻擊(DOS)
另一個沒有放入安全模型的領域是關于將權限映射到系統用戶,代碼以這個用戶的名義來運行。這中訪問控制在unix系統中較為常見,它基于用戶ID對文件的訪問進行控制。