https://www.informationsecurity.com.tw/Seminar/2024_PaloAlto/
https://www.informationsecurity.com.tw/Seminar/2024_PaloAlto/

觀點

WEB 2.0安全拉鋸戰

2008 / 01 / 14
編輯部
WEB 2.0安全拉鋸戰

兩代web應用程式比較
現今全球Web應用程式的發展,因為Ajax技術被廣泛使用的緣故,最近又燃起了一股新的契機。當然,也由於有這些技術,Web站台不但得以呈現出更多元的面貌,同時也提高了互動性-給定用戶等同桌面程式的使用經驗,不過,因為屬於伺服器端應用程式的關係,所以擁有容易佈署和維護等特點。是故,企業會願意採納這項技術,不單是能將佈署成本壓至最低,此外,還能博得用戶們的滿堂采!

然而,在這些科技和技術的背後,同樣也面臨到安全風險上的考驗。傳統Web應用程式和新一代Web 2.0 Ajax應用程式的區別,就在於套用在用戶端上的程式邏輯,以及在資料處理量和處理過程的不同。用戶端這邊不再僅止於簡單的處理HTML和Flash而已,取而代之的,是以JavaScript形式出現的複雜程式邏輯,有時還會伴隨著大量XML形式或JSON(JavaScript Object Notation)形式的結構性資料,而上述會造成兩個層面問題的產生:其一,就是將企業的商業處理邏輯赤裸裸地攤在使用者面前,另外,就是還得面對應用程式接下來可能發生的全新安全威脅問題。所以,企業們必須去瞭解這些應用程式的特性,查看這些與Ajax相關的威脅,是否為全新的種類?亦或只是另一種看待過去分散式Web應用程式安全問題的途徑?



更貼近了解AJAX
Ajax就像一個抽屜般,收納了其實已存在多時的開發實作技術;在其核心層面,就是藉由瀏覽器向伺服器端傳遞一連串非同步的請求,並透過客製化的JavaScript程式來處理這些請求回應,而非單單只是把處理結果秀出來而已。不過,目前它也帶出一些附屬技術:諸如視覺效果(visual effect),互動元件-rich-text editor,資料序列化(data serialization)等,多到不勝枚舉。然而,相較之下,大多數這些東西不過只是附屬品而已,其最主要的目的:還是讓瀏覽器扮演非同步的用戶端角色,並繞過瀏覽器預設回應行為,對用戶請求作處理。

Ajax程式既不屬於Web service一種,也非RESTful之類的技術,更不是設計拿來讓其他軟體消費用的東西。從其功能面上來看,Web-based的應用程式原本就是被設計只透過瀏覽器來使用的,所以,要保護該種應用程式就得先學會保護用戶本身的安全-因為用戶們可是很寶貝他們的個人資料;而應用程式當然就要能夠保護他人資料和維持自身程式碼的安全。在Ajax應用程式的處理情境當中,避免私密資料從用戶端洩露出去給伺服器端是必要的,同樣道理,位於應用層使用者的資料,也不應當可以從伺服器流到用戶端才對,也就是說,只要是關於機敏性的資料,都不該被任何用戶端取得。

另外,為了定義出什麼是新威脅?相當重要的一點,就是程式開發暨安全團隊得去瞭解舊有Web 1.0程式的威脅所指稱的是那些東西?比方像是XSS(cross-site scripting)跨站台攻擊和SQL注入式攻擊等。(參見『Web應用程式的攻擊類型』) 接著,當在瀏覽器裡加入了使用JavaScript碼來遞送和接收非同步訊息(通常會包含結構性資料在內)時,企業可以查看到底有何改變了?而這整件事就會變得明朗開來:毫無任何事物有本質上的改變,看來是沒有新形態的攻擊,有的只是用新的途徑和方法去幹壞事。


新舊威脅如出一轍
在Secure Code這本著作當中,該書的共同作者Michael Howard和David LeBlanc定義出保護應用程式安全的兩大準則:「在沒有通過檢驗之前,請認定所有輸入的資料都是有問題的。」 及「任何資料從不受信任環境跨越到受信任環境的界限中間,都必須先過檢驗這一關。」

上述二句箴言代表著,在Web應用程式傳遞訊息的過程當中,任何資料從用戶端要送達到伺服器端之前,必須先檢驗過,才能將其用於接下來的任何環節。通常,使用者所提供的資料會被用在三個地方:經過一串SQL請求後,被存放在資料庫裡;被拿來當成運算的值,或者當成輸出資料,導回給用戶。

同時,用戶們當然也可以採取以下兩種方式將資料遞送給伺服器:把資料先經過URI編碼(URI-encoded)後送出-除了querystring以外,也可以是以HTTP POST的方式;另外,或者是利用HTTP header-不管是透過cookie,還是其他的HTTP header方式。

不過,說來說去,Ajax並沒有動用任何方法改變這些事物。況且,Ajax應用程式在使用用戶端資料的本質上,也不是採取什麼樣新方式。它們也許輸出的只是一小片段的HTML碼,但絕不會是一整個HTML網頁;再者,它們也只會在用戶端上執行資料的運算,而不是在伺服器上幹這些事。不過,Ajax程式仍然要儲存資料,因為無論是執行運算或其他請求,也都絕對少不了它。

同樣地,XMLHttpRequest物件就是非同步處理方式的主幹,因為它依舊是發送HTTP請求,和接受HTTP回應的機制,這也意謂著,資料遞送到伺服器的方式,就跟過去以來是一模一樣的?!「就安全領域而言,算得上了無新意,驗證資料輸入仍舊會是我們唯一的安全考量。」,SPI Dynamics的首席研究員Billy Hoffman說。不過,這也並非表示程式開發者就無須擔憂事情的發生-伺服器端上良好的輸入驗證需求是不變的,然而,Ajax卻也加大了程式開發者負擔,即他們必須得提供用戶端更完善的輸入檢驗方式。再者,倘若以此觀點來思考,我們會知道,當用戶端一旦流行起使用複雜的JavaScript,那麼,典型的攻擊方式和要發現這些攻擊手法的方法就會改變。部份的攻擊行為會包括像是:

隱藏類型的XSS跨站台攻擊
XSS攻擊已存在好一陣子了。在標準的Web應用程式當中,每一個不管是用GET或POST的方式發送到伺服器端的請求,都會產生出完全由瀏覽器來讀取和執行的回應訊息,而惡意的JavaScript不是被放在
倘若從伺服器返回的訊息,包含了可執行的JavaScript程式碼,那麼,該程式便會在已載入頁面當中配合情境來執行,可是,它卻無法被用戶透過「檢視原始碼」的方式觀看到,因為現階段只顯示原有被瀏覽器取回執行的頁面,並非反應當前DOM的狀態。這不是什麼新技術,而且除非你能使用DOM解譯工具,否則,尤其是那些躲躲藏藏的惡意程式碼,更是讓人難以捉摸。

JSON,XML和其他資料序列化方式
瀏覽器只透過兩種方式把資料送給伺服器,當然,Ajax程式也依舊如此。不過,在資料的展現上,它卻有重大的改變(參見『切斷危險的JAVA臍帶』)。過去,資料乃透過成對的變數名稱和其值來進行傳遞的,它們展現出來的形式,會是以如下的簡單數值或陣列數值來表示:
POST /user/update
name=Justin&age=35&location=Durham%20NC

一般而言,伺服器端上的檢驗程式會去處理這些經URI編碼過之資料的值,並再將其拿來作某些用途。接著,被獲得的這些值,目的地便可能是資料庫,所以檢驗程式最主要的功能,就是確保資料當中沒有包含可執行的SQL陳述式,或者能跳過檢驗程序直接執行SQL請求的部份-查看是否採用單純的參數,而非是那些能串連成請求的字串。也許,之後程式會以「age」變數計算某些數值,因此,確保它是否為數值型態的變數也是同等重要。最後,HTML回應則可能會使用「name」變數的值,來作為用戶端可見的結果之一,此外,還要再三確認它不包含有可執行之JavaScript程式碼。

然而,Ajax程式卻不會以此種方式展現資料。它們並非發送一整串經過URI編碼過的資料集合,而是採單一對的變數名稱/值,並使用某些序列資料形式進行展現。以下雖然同為POST,但卻以JSON序列化的方式表示:
POST /user/update
user={“name”:”Justin”, “age”:”35”, “location”:”Durham, NC”}

於是,現在伺服器端的程式便會衍生出不同的驗證問題,其中之一會包含了兩個步驟:將資料解構打散,接著再一步步地檢驗各別變數值的合法性和有效性。但是,JSON也並非此種資料展現的唯一選擇?!XML在資料序列化當中,也大量被採用,就連現在YAML(YAML Ain''t Markup Language)也遇到相同的情形,只不過大多是出現在以Rails-based為主的網站而已。再者,目前也升起一股microformat的浪潮,或者是特定的資料語意(syntax)用法-其目的是為每一項語意打造特定的語意分析器(parser),將資料展現的效果利用到極致。不管是上述何種情況,伺服器端的驗證程序,現在會面臨到兩個問題,而不是一個,因此,複雜度也會有所提高。

過渡執行程式與隱藏性POST發送方式
過去,無論是惡意JavaScript程式,覆寫網址(rewritten URLs),或者是其他在用戶端製造連往伺服器請求的攻擊行為,都是可以被使用者看見的,因為當請求發送出去的同時,瀏覽器會在網址列上顯示出網址。這表示,最起碼使用者是有可能發覺問題的存在-只要去檢視導覽頁面所瀏覽的網址就辦得到。但是,在Ajax的程式中,只透過隱藏的後門通道(XMLHttpRequest)發送訊息的話,那麼,要查覺不對勁的情況可就是難上加難了?!倘若沒有藉由網路探嗅(network sniffer)工具的幫忙,或者利用能辨識XHR流量的瀏覽器元件,要看到這些代替使用者送出的請求,是絕對辦不到的。

在傳統的Web應用程式之中,服務請求是會被看到的,並且任以下兩種情況的一種都會觸發它們:點選網址或者是送出form裡頭的資料。不過,在Ajax程式中,請求卻是隱藏起來的,而且只有在不同的用戶行為下才會觸發服務請求,比方說,滑鼠滑過某一個網頁元素上,或是進到/跳離某個欄位區域。再者,許多的網站還會更進一步地「幫忙」:在沒有使用者觸發事件的情況下,利用過渡執行程式(period executor)發送服務請求,像是藉由JavaScript所擁有的timeout能力,部份應用程式就能建立一個廻圈,限定在每幾秒內就觸發一次服務請求,有時候送出的是應用程式所提供的資料,有時候卻是用戶所提供的資料。這種服務請求不僅被隱藏起來,而且當用戶完全離開整台電腦時,依舊仍可能繼續發生。




固守根本
Ajax應用程式需要新的安全防護之道?看來,問題仍然要回到檢驗用戶所提供的資料上,並確保不論使用者送出那些資料,都應該會是某種有效的資料展現格式。就Ajax世界而言,使用者所提供的輸入資料,或多或少都會有些許形式上的差異-像是JSON資料序列格式,而回傳給用戶端訊息,可能也不會是完整的HTML碼-或許是XML,JSON之類的資料序列格式。這些改變在在都暗示著程式複雜性的存在,但是,在安全防禦上並沒有太大變化,解決之道仍舊跟以前是一樣的。

過濾用戶端輸入,檢驗系統端輸出
不管資料遞送到伺服器的機制為何?最後,應用程式只會對其執行三件事:儲存(store),改變(modify),以及導向(render)。伺服器端針對資料使用上的檢驗,應該要明確:分別是SQL字串濾除(SQL scrubbing),資料型別查核(type enforcement),以及HTML編碼(HTML encoding)。有時候,在單一的服務請求當中,資料會被應用在多種方式裡頭,後面接著才會執行各項適當的檢驗方法。

我們將可能的系統輸出分作以下四類:
1) 導向成HTML頁面
HTML頁面的呈現,有時是透過字串的控制,有時則是使用樣板引擎,或者是導向瀏覽器後所得到的結果。

2) SQL陳述式執行
假設我們將應用程式,想成是由Web伺服器控制之程序上所執行的程式碼,那麼,SQL請求就只是讓資料庫系統所使用的應用程式,為了產出用的另一個輸出。更何況,我們還能運用一些可避免因透過參數傳遞遭SQL注入式攻擊的高階工具,來打造出SQL請求。

3) 以非HTML格式輸出導向至瀏覽器
一般而言,這些輸出會是結構性資料-像是JSON,XML,YAML,或是microformat格式,甚至是任何一種MIME型式的輸出文字展現。

4) 存成檔案格式
資料被附帶成以檔案型式,或是其他檔案格式儲存起來。

每一項輸出作業,都應該再一次地對應到該被執行的檢驗程序。接下來,如果不想因為程式呼叫就去執行JavaScript程式的話,那麼,要生成HTML碼前,就應該要先濾除掉
Innocent Div


在上述案例裡,這個具可執行的JavaScript程式碼,被嵌入當成是正常HTML架構下的事件屬性,而非文件標籤的主體。不過,要確保類似該段JavaScript不被執行的唯一可靠方式,就是在去除