近來Java 7被證實有若干個安全性漏洞,也讓許多人對Java的安全性有了很大的疑慮。究竟這些安全性的問題的影響層面如何?對現行應用程式所造成的衝擊又有多少呢?

讓我們先回到Java的程式語言來看,有趣的事,在Java設計的時候,特別針對安全性做了一些考量,希望可以解決一些舊有常引發安全性問題的設計。除此之外,面對了新的應用環境(主要是網際網路)及需求,也加上了一些機制,希望能夠對應用程式的運行,提供安全性的保護。

Java在應用程式的安全性上有好幾層的設計,首先,在語言本質便考慮到一個重要的特性,那麼便是避免記憶體的違法越界存取。例如Java由於應用程式對記憶體的存取動作,都受到虛擬機器的管理及限制,所以,舉凡存取空指標,以及對陣列的越界存取動作,都會不被虛擬機器所允許,進而擲出諸如NullPointerException,以及IndexOutOfBoundsException的異常,阻止應用程式做出了錯誤的記憶體操作。

這樣的設計,一方面可以增加程式的穩固性,不致於讓程式因為臭蟲造成的違法記憶體存取就直接崩潰、異常終止,另一方面,也能幫助程式設計者很快找到程式的臭蟲所在。在一些語言中,有時候錯誤的記憶體存取操作,並不是那麼容易除錯。

不過,除此之外,藉由這樣的機制來提升應用程式的安全性,也是一個十分重要的目的。

在Java之前,有一些允許應用程式做低階記憶體操作的程式語言,例如C或C++,以它們寫成的應用程式,由於其操作記憶體位置的自由度,使得傳統上著名的「緩衝區溢位攻擊(buffer overflow attack)」方式得以被運用。一旦成功發動了緩衝區溢位攻擊,就能夠執行攻擊者想要植入的程式碼片段,這當然十分嚴重。而為了杜絕緩衝區攻擊,這些可能會有緩衝區溢位攻擊的語言,也透過改良程式庫的方式,在程式庫的層級上,提供可安全存取記憶體或字串空間的的程式庫。不過,即使如此,在語言的本質上,還是有著如此的問題。想要避免緩衝區溢位攻擊,還需倚靠程式設計者的小心提防。

不過,Java語言在本質上杜絕這一點。在純Java的環境中,虛擬機器會試圖攔下此類的攻擊。當然,若是非純Java的情況,使用像Java Native Interface的方式去整合原生語言,所寫成的程式碼,還是有可能招致此種攻擊。此外,像確保物件轉型時的型態安全性,也是Java避免其應用程式遭受攻擊的機制。

史上有很多著名的攻擊,包括從最早的網際網路蠕蟲Morris Morm開始,都是源自於對緩衝區溢位攻擊特性的利用。所以說,Java在本質上試圖杜絕和此相關的安全性攻擊。

因應遠端程式在本機端執行的保護設計

除了在本質上增加安全性之外,Java也會對所要執行的程式碼做靜態的檢查,這檢查主要是透過bytecode檢驗器(bytecode verifier)來做的,包括了檢查是否進行了非法的程式跳躍(即分支的流程控制)、資料是否全經初始化而且所有的參照(reference)皆具型別安全性,以及對函式的存取權限皆符合定義、等等。透過bytecode的檢驗器,可以在靜態時期,對欲於Java虛擬機器上的bytecode做檢查,找出一些在靜態時期就可以檢查出來的問題。

此外,Java在設計時,即考慮到於動態時期執行遠端程式碼的需求,也就是說,其實你可以動態地從任何地方,包括從網路上即時取得一段程式碼,接著在本機端的虛擬機器上予以執行。一個最典型的例子,就是Java Applet。

各位可以想像,當我們使用瀏覽器瀏覽一個需要執行Applet的網頁時,其實Applet可能從未在本機端安裝過,但是瀏覽器上執行Applet的虛擬機器,會動態的從網路上取得Applet的程式碼,以及伴隨的其他程式,接著執行這個本機「素未謀面」的程式。

允許遠端程式以如此動態的方式在本機端執行,當然是一種極具擴展性及彈性的方式,這種方式也被稱為「行動式程式碼」。不過,從功能面上來看很吸引力,但是,更嚴肅的安全性問題也伴隨著強大的彈性而來。

在過去,攻擊者透過網路進行攻擊的方式,便是想盡辦法想要在遠端植入程式碼,以便完全自己的特殊目的。而防守的方式,自然是千方百計地杜絕外界執行任意的程式碼。而在這種「行動式程式碼」的架構下,卻反其道而行,將自己的門戶洞開,開放讓外界、可以說是無法信任的程式碼,進來自己的執行環境來執行。

為此,Java有一些對應的設計,首先,它利用類別載入器(ClassLoader)的概念,將來自於不同信任來源的程式碼,以不同的類別載入器畫分載入,並予以不同的授權範圍。這麼一來,來自於不同來源的程式碼,就可以套用不同的權限來予以管控。例如,來自於本機端的程式予以最大的權限,而來自於網路上、不足以完全信任的程式碼,例如Applet,就可以套用較為保守的權限,以保護本機的資源及安全,而這個管控的機制是透過所謂的安全管理器(SecurityManager)來進行的。這種將具有疑慮、不足以完全信任的程式碼,置於一個受限的環境來執行的方式,就被稱為沙盒(sandbox)。意思是,即使讓小孩子在裡頭玩沙,就算弄得亂七八糟,也不會影響到沙盒外界的環境。

Java Applet執行上的問題

而最近傳出的Java安全性問題,其實都是圍繞在Java Applet的問題上面。有一類的問題是當使用者瀏覽別有居心的網頁時,依照Java的安全性機制,理論上瀏覽器的Java Plug-in會詢問使用者是否允許執行,而利用攻擊的手法,這件事會略過。也就是說,即使瀏覽器的使用者沒有同意,Java Plug-in還是會將Applet下載起來執行。

假若,瀏覽器只是將Applet在未經使用者同意就下載來執行,也就算了,惡意的Applet程式雖然還是可以發動一些型態的攻擊,但或許闖不了大禍。但是,再搭配另一些攻擊的方式,也就是繞過沙盒檢查的攻擊,這兩帖毒藥一起服用,危害就大了。

在沙盒的保護下,未信任的Java Applet能做的事有一定的限度,像是它不能夠讀取本機端的檔案、不能在本機上建TCP的socket供外界連入,也不能連往除了下載程式碼的其他遠端機器。然而,一旦可以繞過沙盒機制(也就是安全檢查器)的檢查,那麼程式碼便無異於本機端所執行的程式碼,可以完全不受沙盒所限制。

二者的效用前後相連,使用者只要一點擊瀏覽器惡意的網頁(例如被電子郵件釣魚),將在無任何預警的情況下,執行起一個權限不受控制的Java程式,這嚴重性當然非同小可。因為此時,該Applet程式將有權限讀取你本機端的所有檔案,也有能力把檔案傳送到它想送去的伺服器之上。

有能力繞過沙盒的傷害當然是頗為嚴重,所幸這些都是在瀏覽器上執行 Applet 的問題,而非獨立執行之Java應用程式的問題。不過,某些報導的寫法,很容易讓人以為是Java應用程式也有一樣的問題,這二者之間卻是天差地遠。

現在絕大多數的Java程式,都是獨立執行的 Java 應用程式、 Web 應用程式、或是運行在 Android 上的行動應用程式,它們都和這個問題無關。這些報導方式,的確有可能引起許多人對Java的恐慌。甚至有些僅僅只是在伺服器上執行Java Web應用程式的公司,也擔憂起是否受到這樣的安全性威脅所影響。

Java 語言的興起,幾乎可以說是因為Applet大受歡迎所成就的,不過時至今日,Applet 當初的作用,在實際應用裡,絕大多數也都被其他的技術或平臺取代,因此,我們已經很少看到新的應用程式使用Applet來開發了。

或許,這些圍繞在Applet執行的安全性問題,會使得接下來有些瀏覽器,會考慮讓 Applet 的運行環境預設不開啟,甚至成了壓倒Applet的最後一根稻草。

作者簡介


Advertisement

更多 iThome相關內容