Java語言擁有三大特征
平台無關性
網絡移動性和安全性
而Java體系結構對這三大特征提供了強大的支持和保證
本文著重介紹Java體系結構對支持信息安全的原理和使用方法
Java體系結構 Java的體系結構如下圖所示
首先Java的源代碼Java文件由編譯器編譯成Java的二進制字節碼class文件
然後class文件由Java虛擬機中的類裝載器進行加載
同時類裝載器還會加載Java的原始 API Class文件
類加載器主要負責加載
連接和初始化這些class文件以後
就交給虛擬機中的執行引擎運行
執行引擎將class文件中的Java指令解釋成具體的本地操作系統方法來執行
而安全管理器將在執行過程中根據設置的安全策略控制指令對外部資源的訪問
Java的執行方式不是編譯執行而是解釋執行
不同平台上面相同的源代碼編譯成符合Java規范的相同的二進制字節碼
然後再交給支持各自平台的虛擬機去解釋執行
先編譯
後解釋
再執行
三步走的方式使得Java實現了
一次編寫
到處運行
如果Java應用使用的是
%標准Java API並且沒有直接調用本地方法
那就可以不加修改地運用在多種平台上
這樣的平台無關性使得在異構的網絡環境或者嵌入式方面的應用更方便和現實
Java的網絡移動性帶來了一種全新的軟件模式
在分布式處理模式的基礎之上
可以將軟件和數據通過網絡傳送到客戶端去
這樣確保了客戶端有必備的軟件來浏覽和操縱通過網絡傳輸的數據
Java體系結構支持把單一的執行文件切割成小的二進制字節碼文件Class文件
而這些文件可以按照應用的需要動態連接
動態擴展
Java體系結構對安全性的支持主要是通過Java語言本身安全性
虛擬機的類加載器和安全管理器以及Java提供的安全API幾個方面來實現
防止惡意程序的攻擊
程序不能破壞用戶計算機環境
防止入侵
程序不能獲取主機或所在內網的保密信息
鑒別
驗證程序提供者和使用者的身份
加密
對傳輸交換的數據進行加密
或者給持久化的數據進行加密
驗證
對操作設置規則並且進行驗證
Java信息安全的必要性 隨著互聯網應用越來越廣泛
並且互聯網其本身獨特的資源共享性
因此能夠按照用戶需求及時准確獲得信息和處理信息的應用對用戶而言就相當重要
這也是Java得以迅速發展和被廣泛接受的原因
但同時網絡也提供了一條攻擊接入計算機的潛在途徑
特別是當用戶下載網絡軟件在本地運行
這就要求Java能夠對病毒/木馬的問題加以防范
對信息以及本地環境進行保護
比如我們浏覽一個網頁的時候
網頁上的Applet可能會自動下載並且運行
而這個Applet完全有可能來自不可靠的地方
又或者我們使用通過JINI服務查找到的網絡上不可靠的服務對象來獲得服務
如果沒有Java體系結構提供的安全機制
這就很有可能引入了一個懷有敵意的程序造成信息丟失
資料洩密
相信偽造數據和修改本地計算機安全設置等等後果
帶來未知的嚴重後果
Java語言本身安全性 Java語言的設計者們是在C++的基礎上設計出來Java的
因此與C++相比它的語法更加簡單清晰
結構
單元
運算符重載
虛擬基礎類等在Java中都沒有采用
並且取消了多重繼承而采用實現多個接口的方式
這樣能降低開發人員犯錯誤的幾率
幫助他們寫出更安全的代碼
Java中去除了C++語言中的令人費解
容易出錯的
指針
用列表
堆
哈希表等結構來代替
避免了任何不安全的結構
Java也沒有索引核查的數組訪問
因為這往往會導致不定的
不可預測的程序操作
它所有的數組訪問都必須先檢查是否越界
Java要求所有的變量在初始化以前不能使用
對於基本數據類型變量都會自動地賦給某個初始值
避免了未初始化變量獲取內存信息
所有這些都使得程序不能訪問任意的內存地址
對於內存中的實體信息只能通過有權限的對象進行訪問
而不會出現象C++那樣把類型指針強制轉換成內存的指針
然後通過內存查找的方法找到私有的變量
Java分配內存對於開發人員來說是透明的
開發人員使用new方法新建對象
這時候虛擬機就會從堆內存中找到合適的內存空間
開發人員不需要也不能夠進行干預
而對於內存的回收
Java避免了開發人員明確干預對象的回收
比如C的free或C++的delete命令
避免了開發人員無意間對內存的破壞
Java采用虛擬機的
垃圾回收
機制來實現的內存自動管理
釋放不再被使用的內存資源
內存回收器就像一台垃圾收集車
但是和我們在大街上看到的收集車
僅僅收集大家放在垃圾桶裡面的垃圾不同的是
它還要到你家裡去幫你找出那些東西是不要用的垃圾
然後把這些東西拿走
最後還要整理家裡的空間
騰出最大的空間讓你放新東西
Java的內存回收器目的就是找到不再引用的對象
釋放內存空間
並且需要整理內存的碎片空間
盡量避免出現
內存不足
的情況
對於在網絡中交換的序列化對象很容易在重建對象的時候訪問到對象的私有信息
這時候Java提供了兩種辦法來保護信息
一種就是采用給變量加上transient關鍵字的方法
這樣對象序列化的時候就不會讀寫該變量
另一種就是在實現Externalizable接口而不是Serizlizable接口
這樣對象就只能通過writeExternal和readExternal方法來保存和重建
其他方法無法進行了
以上這些都是Java語言本身對信息安全提供的基礎
類加載器 雖然名字叫類加載器
但是實際上Java虛擬機中的類加載器不光要負責加載而且要負責連接和初始化應用程序需要用到的Java類型
加載就是把二進制形式的字節碼讀入虛擬機中
而連接就是給這個已經讀入的類型分配類變量內存以及把類型中用到常量池中的符號轉換為直接引用
最後的初始化過程就是賦給類型變量合適的初始值
類加載器為加載的類提供了不同的命名空間
統一源代碼生成的字節碼被加載到同一個命名空間中
相同命名空間不能加載類名相同的類
同一個命名空間內的類可以直接進行交互
而不同的命名空間的類是不能交互的
除非顯式地提供了交互機制
通過命名空間和類成員訪問權限的設置保護了被信任的類邊界
類加載器分成了啟動類加載器
標准擴展類加載器
路徑類加載器和網絡類加載器四種
啟動類加載器從本地系統中加載原始的Java API類
用來啟動Java虛擬機
而其他三種加載器是在運行時加載用戶定義的類
標准擴展類加載器加載的是不同虛擬機提供商擴展的標准Java類
而在classpath中的類由路徑類加載器來加載
網絡類加載器加載通過網絡下載得到的類文件
每一種加載器在加載類的時候都會建立一個加載器實例
類加載器采用雙親委派鏈模式(這個模式很類似GOF在《設計模式》一書中提到的責任鏈模式)除了啟動類加載器以外
每個類加載器都有自己的
雙親
一個類可以通過有三種方法定義自己的雙親
第一種通過引用
比如A類中引用了B類(即A和B有關聯關系)
那麼B類的加載器就會作為A類的加載器的
雙親
早於A類加載
第二種使用loadClass方法來自定義
雙親
這時被load的類的
雙親
即本身這個類加載器
第三種在沒有采用前兩種的情況下使用的默認方式
默認把啟動類加載器作為
雙親
在加載過程中
當發出加載請求的時候
加載器首先詢問它的
雙親
――路徑類加載器――來查找並加載這個類
而這個加載器也向它的
雙親
請求加載
一層一層請求上去
直到啟動加載器獲得請求
來查找並加載這個類
如果這個類沒有被加載並且查找不到
返回結果給它的子加載器
由子加載器加載
直到請求返回給原來的加載器
這時還沒有加載成功的話
由網絡類加載器試圖從網絡中尋找並下載
如果還不成功將拋出NoClassDefFoundError異常
這個過程保證了啟動類加載器可以搶在標准擴展類加載器之前加載類
而標准擴展類加載器又可以搶在路徑類加載器之前加載類
最後才由網絡類加載器加載
比如應用被試圖加載一個帶有惡意代碼的java
lang
String類
因為它本來是Java API的一部分
它們加載到的命名空間可以得到被信任類的特殊訪問權限
但是由於啟動類加載器是最早被加載的
所以java
lang
String只會被啟動類從Java原始的API中加載
而帶有惡意代碼的java
lang
String類不會被加載進來
這樣有效的保護了被信任的類邊界
類加載器中還包括了一個類型檢查的功能模塊
它負責保證程序的健壯性
它在類型的生命周期中要進行四次檢查
第一次檢查是在加載的時候
主要檢查二進制字節碼的結構
首先格式要滿足Java語言定義的規范
然後要保證將要加載的類字節碼是一組合法的Java指令
第二次檢查是在連接的時候
主要是類型數據的語義檢查
保證字節碼在編譯時候遵守了規范
比如對final類不會派生出子類
也不會重載final的方法
每個類只有一個超類
沒有把基本數據類型強制轉換成其他數據類型
第三次檢查也是在連接的時候
關注於指令的結構
保證指令的操作數類型和值正確
操作數堆棧不會出現上溢出或者下溢出
最後一次檢查在動態連接的時候
主要檢查類型中的符號引用被解析時是否正確
以上的問題都會產生惡意的行為所以必須在運行前進行檢查
而一部分檢查工作會在虛擬機運行字節碼的時候檢查
比如數組越界
對象類型的轉換等等
一旦檢查發現了問題就會拋出異常
使得程序不被執行
類加載器避免了出現某些懷有敵意的人編寫自己的Java類
而這些類方法中含有跳轉到方法之外的指令
導致虛擬機的崩潰和保密信息被獲取的可能
保證了程序的健壯性
也不會出現替代原有Java API類的惡意代碼被運行的情況
並且類加載器防止了惡意代碼去干涉善意的代碼
守護了被信任的API類庫邊界
確保了代碼可以進行的操作
安全管理器 安全管理器為Java虛擬
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19524.html