2012年3月2日 星期五

(轉) Web安全筆記 (1~7) (由淺入深)

1.web應用程序改採用的防衛機制的幾個核心構成:
1、處理用戶對應用程序的數據和功能的訪問,以防止用戶未經授權訪問。
2、處理用戶的輸入,以防止惡意的輸入導致未預期的行為。
3、處理攻擊,以確保應用程序在被直接攻擊時作出恰當的行為,如採取適當的防禦和進攻性措施,以挫敗攻擊。
4、通過使管理員能夠監控應用程序的活動和配置應用程序的功能來管理應用程序本身。

1.1處理用戶訪問

大多數web應用程序都使用下面的三重相關的安全機制來處理訪問:
1、驗證
2、會話管理
3、訪問控制

驗證
驗證機制在一個應用程序的用戶訪問處理中是一個最基本的部分。驗證就是確定該用戶的有效性。大多數的web應用程序都採用常規的驗證模型,即用戶提交一個用戶名和密碼,應用程序檢查它的有效性。在安全性很重要的應用程序中,如在線銀行,這個基本的驗證模型常增加額外的證書和多級登錄過程。在安全性要求更高的時候,其它的一些驗證模型可以被用,如客戶端證書,智能卡或挑戰/應答(challenge-response) tokens。

challenge-response tokens的過程:
用戶要求登錄時,系統產生一個隨機數字串發送給用戶。用戶將這個串輸入到token設備中,token設備將這個串與用戶的秘密口令按特定的算法進行運算並產生一個回應串發送給系統,系統用同樣的算法做驗算即可驗證用戶身份。

除了核心的登錄過程外,驗證機制也常採用其它的一些輔助功能,如自註冊(self-registration,比如註冊後通過郵件中的鏈接激活帳戶),帳戶恢復以及密碼更改功能。儘管驗證機製表面上簡單,但是驗證機制在設計和實現方面卻存在著廣泛的缺陷。一般的問題可能使一個攻擊者能夠識別其他用戶的用戶名,猜測他們的密碼或者通過利用驗證的邏輯缺陷繞過這個登錄函數。當你攻擊一個web應用程序時,你應該花大量的注意力在該web應用程序所包含的各種驗證相關的功能方面。驗證方面的缺陷將使你能夠未經授權地訪問敏感數據和功能

1.1.2會話管理

處理用戶訪問的下一個工作是管理授權用戶的會話。在成功登錄到應用程序後,用戶將從他們的瀏覽發送一系列的HTTP請求來訪問一些頁面和功能。同時,該應用程序將接收無數來自不同用戶的其它的請求,有授權的用戶,也有匿名的用戶。為了實施有效的訪問控制,應用程序需要一個方法來識別和處理這一系列來自每個不同用戶的請求。

實際上大多數的web應用程序都通過為每個用戶創建一個會話和發送給用戶一個令牌(token)來識別會話。會話本身是位於服務上的一套數據結構,它被用來跟蹤與應用程序交互的用戶的狀態。令牌是一個具有唯一性的字符串,應用程序將它映射到會話。當一個用戶已經收到一個令牌時,瀏覽器在隨後的每次HTTP請求中會自動將這個令牌提交給服務器,以使得應用程序能夠將該請求與用戶相關聯起來。儘管許多應用程序使用隱藏的表單域或URL查詢字符串來實現這一目的,但是HTTP cookies是傳送會話令牌的標準方法。如果一個用戶在指定的時間內沒有產生一個請求,那麼會話將被認為結束。對於之後的訪問,web應用程序會要求你重新登錄。

就攻擊而言,會話管理機制高度地依賴於它的令牌的安全性。針對會話管理機制的多數攻擊都是試圖損害發送給別的用戶的令牌。有可能的話,一個攻擊者可以偽裝成受害的授權用戶來使用web應用程序。這一漏洞主要來自於兩方面,其一是令牌生成的方法的缺陷,使得攻擊者能夠猜測到發送給別的用戶的令牌,其二是令牌的後續處理的方法的缺陷,使得攻擊者能夠捕獲別的用戶的令牌。

有少部分的應用程序通過另外的識別方式省掉了會話令牌的需要,比如,如果一個HTTP的內建的授權機制被使用的話,那麼瀏覽器對於每次的請求都自動重新提交用戶的證書,使得應用程序能夠直接從證書識別用戶。也存在其它別的方法,應用程序存儲狀態信息在客戶端而非服務器上,這些狀態信息通常採用加密的形式以防止被篡改。

1.1.3訪問控制

處理用戶訪問的最後一步是正確決定對於每個獨立的請求是允許還是拒絕。如果前面的機制都工作正常,那麼應用程序就知道每個被接受到的請求所來自的用戶的id。它據此決定用戶對所請求要執行的動作或要訪問的數據是否得到了授權。
訪問控制機制通常需要根據對應用程序的不同部分或不同類型的功能的考慮,實現一些小而好的邏輯。一個應用程序可能支持許多不同的用戶角色,每個都牽涉到特定權限的不同組合。個別的用戶可能會被允許訪問該應用程序所容納的整個數據的一個子集。特定的函數能夠實現事務限制和其它的檢查,所有這些都需要基於用戶的id來得到正確的實施。
由於訪問控制本身的複雜性,這使得它成為使得一個攻擊者能夠獲得未授權訪問數據和功能這一安全漏洞的常見根源。開發者經常對用戶會如何與應用程序交互作出有缺陷的假設,以及經常由於省略了對某些應用程序功能的訪問控制檢查而造成疏忽。由於對於每項功能都需要重複相同的檢查,所以探查這些漏洞通常是十分費力的。然而由於訪問控制缺陷的普遍性,當你攻擊一個web應用程序時這種努力是值得的。

1.2 處理用戶的輸入
很多針對web應用程序的攻擊都涉及到提交未預期的輸入,它導致了該應用程序設計者沒有料到的行為。因此,對於應用程序安全性防護的一個關鍵的要求是它必須以一個安全的方式處理用戶的輸入。基於輸入的漏洞可能出現在一個應用程序的功能的任何地方,並與每上通常使用的技術類型相關。對於這種攻擊,輸入驗證是常用的必要防護。不存在通用的單一的防護機制。

1.2.1各種類型的輸入
一個典型的web應用程序在不同範圍形式內處理用戶提供的數據。某種類型的輸入驗證可能對於所有這些輸入形式是不可行的。
在許多情況下,一個應用程序對於特定的輸入項能夠實施非常嚴格的驗證檢查。比如提交給登錄函數的用戶名可以要求最大長度和只能包含字母。
在另外一些情況下,應用程序必須容納更大範圍的可能性的輸入。比如提交給一個個人信息頁面的地址字段,它可以包含字母、數字、空格、連接符,撇號以及其它字符。對於這種類型,仍然需要加以可行限制,如不能超過合適的長度,以及不能包含HTML標記。
在某些情形下,一個應用程序可能需要接受來自用戶的任意的輸入。比如,一個blog應用程序的用戶,他創建的博客的主題的web應用程序攻擊,那麼他提交的內容則可以包含明顯的所要討論的攻擊字符串。該應用程序需要以一個安全的方法把這些輸入存儲在一個數據庫中並寫到磁盤上,以及回顯給用戶。所以該應用程序就不能因為輸入看起來有潛在的惡意簡單拒絕。
除了來自用戶的瀏覽器的各種輸入外,典型的應用程序也接受從服務器到客戶端,然後回傳給服務器的數據。這些項目包括諸如cookies和隱藏的表單字段這些,它們不會被這個應用程序的普通用戶所看到,但是對於攻擊者來說是可見和可修改的。在這些情況中,應用程序可以對所接收的數據進行特定的驗證。例如要求參數必須有一個指定數值集中的值,如表明用戶所偏愛的語言的cookie,或以一個指定的格式,如一個客戶的ID號。進一步說,當應用程序發現返回自用戶的由服務器生成的數據已經被修改了的話,這通常就表明該用戶正在探測應用程序的漏洞。在此類情況下,應用程序應該拒絕請求並記錄下這個探測事件。

1.2.2 處理輸入的方式
處理用戶的輸入有很多方式.不同的方式適合不同的情形和不同的輸入類型,有些時候一個組合的方式是可取的.
1.2.2.1 黑名單
這種方式通常使用一個黑名單,它包含已知的被用在攻擊方面的一套字面上的字符串或模式.驗證機制阻擋任何匹配黑名單的數據.
一般來說,這種方式是被認為對於檢查用戶的輸入效果最差的一種方式.主要有兩個原因,首先是,web應用程序中的一個典型的漏洞可以使用很多種不同的輸入來被利用,輸入可以是被加密的或以各種不同的方法表示.其二,漏洞利用的技術是在不斷地改進的.有關利用已存在的漏洞類型的新的方法不可能被當前黑名單阻擋.
1.2.2.2 白名單
這種方式採用一個白名單,它包含一套字面上的字符串或模式,或一套標準,它們用來匹配符合要求的輸入.這種檢查機制允許匹配白名單的數據,阻止之外的任何數據.這種方式雖然最有效,但不是通用的,比如撇號和連字符可以被用於對數據庫的攻擊,但是有時應用程序卻應該允許它的輸入.
1.2.2.3 過濾
這種方式下,潛在的惡意字符被刪除,留下安全的字符,或者在進一步處理被執行之前,它們被適當地加密或去掉.
基於數據過濾的方式通常是十分有效的,並且在許多情形中,可作為處理惡意輸入的通用解決方案.比如,針對跨站腳本攻擊的通常的防護是在字符被嵌入到應用程序的頁面之前進行HTML加密.然而如果幾種潛在的惡意數據在一個輸入項中話,有效的過濾是困難的.在這種情況下,邊界檢查方法則是更適用的.
1.2.2.4 安全地處理數據
非常多的web應用程序漏洞的出現是因為用戶提供的數據是以不安全的方法被處理的.在一些情況下,存在安全的編程方法能夠避免通常的問題.例如,SQL注入攻擊能夠通過正確的參數查詢被阻止.在另外的情況中,應用程序功能設計的方法存在內在的不安全性,比如把用戶的輸入傳遞給操作系統的命令解釋器.
安全處理數據的方式不能適用於web應用程序需要執行的每種工作,但是它對於處理潛在的惡意輸入是通常有效的方式.
1.2.2.5 語義檢查
語義檢查用於防止各種變形數據的輸入,這些數據的內容被精心製作來干擾應用程序的處理。然而對於有一些漏洞,攻擊者的輸入在表面看來和普通用戶的輸入是一樣的,說到底檢查就失去了作用。例如一個攻擊者可能會通過改變隱藏的表意字段中的帳號來試圖獲得對他人銀行帳戶的訪問。要阻止這種未授權的訪問,應用程序需要驗證帳號是否屬於該用戶。
1.2.2.5 邊界檢查
對於web應用程序,核心安全問題的出現是因為接受自用戶的數據是不可信任的.儘管在客戶端實現的輸入驗證檢查能夠能夠提高性能和用戶體驗,但是這對於實際到達服務器的數據卻沒有任何擔保.用戶的數據在被服務端應用程序第一時間接受到的一刻就是邊界,此時應用程序需要採取步驟來防衛惡意的輸入.
鑑於核心問題的本質,對於互聯網邊界間的輸入檢查這一問題的思考是很有意義的.哪些是"惡意的"或不可信任的,以及服務端應用程序哪些是"好的"或可信任的.我們給出一個簡單的想法:輸入驗證的角色是清除到達的數據中的潛在的惡意數據,然後把乾淨的數據傳遞給可信任的應用程序.據此,這些數據可以被信任和處理而不做進一步的檢查或考慮可能的攻擊.
當我們開始檢查一些實際的漏洞的時候,會很明顯地發現上面的簡單的想法是不充分的.原因如下:

(1).鑑於web應用程序實現的功能的廣泛性,以及所應用的技術的不同,一個典型的web應用程序需要防衛大量的不同的基於輸入的攻擊.每種輸入攻擊都可能採用了一套不同的數據.針對外部邊界僅設計單一的一個機制來防衛所有這些攻擊是非常困難的.

(2).許多應用程序的函數包含相互牽連的一系列不同的處理,單個用戶所提交的一塊數據可能導致不同組件之間的許多操作,上一個的輸出可能作為下一個的輸入.當數據被傳送時,它可能有所變化,與最初的輸入可能有所不同,這樣一個熟練的黑客可能能夠操縱這個應用程序以在處理的關鍵階段導致惡意輸入的產生,也就是攻擊接受該數據的組件.這對於在外部邊界預見用戶輸入的每塊數據的處理的所有結果來實現一個驗證機制是十分困難的.

(3).防衛不同種類的輸入攻擊可能需要對用戶的輸入執行不同的驗證檢查,這些驗證檢查是不兼容的。例如阻止跨站腳本攻擊可以要求HTML加密“>”為"&gt";而阻止命令注入攻擊(command inject)可能需要阻止包含&和;字符的輸入。試圖在應用程序的外部邊界同時阻止所有種類的攻擊有時是不可能的。

一個使用邊界檢查概念的更有效的模型是,服務器端的每個組件或功能單元把它的輸入當作是來自一個潛在的惡意源。數據檢查除了在客戶端和服務端之間的邊界外,也在這些認為可信的邊界被執行。這個模型對前面列出的問題列表提供了一個解決方案。每個組件針對自身可能的漏洞的特定的輸入攻擊能夠自我防衛。當數據在不同的組件間傳遞時,驗證檢查就可以對前面傳來數據進行檢查,由於不同有驗證檢查是在不同的處理階段被執行的,所以他們之間不會產生衝突。下圖演示了一個防衛惡意輸入最有效的方式,用戶登錄致使對用戶提交的輸入進行了幾步處理,並且每步上都執行了適當的檢查。



(1).應用程序接受用戶的登錄的詳細數據.表單處理檢查輸入的每一項,包括允許的字符、長度是否在指定的範圍內、以及不能包含任何已知的攻擊特徵碼.
(2).應用程序執行一個SQL查詢來驗證用戶的證書.為了阻止SQL注入攻擊,用戶輸入的任何可能攻擊數據庫的字符在構造查詢之前都被去掉.
(3).如果登錄成功,應用程序將把來自用戶的數據傳遞給一個SOAP服務器以檢索他的帳戶的更多的信息.為了阻止SOAP注入攻擊,用戶數據中的任何XML元字符都被適當地加密處理.
(4).應用程序把用戶的賬戶信息回傳給用戶的瀏覽器以顯示.為了防止跨站腳本攻擊,應用程序HTML加密嵌在返回的頁面中的用戶提供的任何數據.

總之,所有牽涉的組件間都應作邊界檢查.情況的變化會導致所涉及的組件發生變化.例如如果登錄失敗後,應用程序會發送一個警告郵件給該用戶的話,那麼任何合併到該郵件中的用戶數據可能需要針對SMTP注入攻擊作檢查.

1.2.2.6 多步檢查和恢復

如果對用戶的輸入沒有進行仔細的多級檢查的話,攻擊者構建的輸入就可能會得逞。當一個應用程序試圖通過刪除或加密特定的字符或表達式來過濾用戶的輸入的話,這種情況就可能會出現。例如,一個應用程序可能試圖從用戶提交的數據中通過去掉表達式<script>來防止某些跨站腳本攻擊,那麼攻擊者可能通過輸入<scr<script>ipt>來繞過這個過濾。這是因為這個過濾沒有被遞歸地使用,當<scr<script>ipt>中間的<script>被去掉後,剩下的還是<script>。

類似的情況就是,攻擊者可以利用多步檢查的順序來繞過這個過濾。例如如果一個應用程序第一是遞歸地去掉<script>表達式,然後是去掉"符號的話,那麼<scr"ipt>就可以成功繞過這個過濾。

另一個問題是在用戶輸入的數據被解密時會發生的。從用戶瀏覽器過來的數據會是以不同方法加密了的數據,那麼就需要對這些數據進行恢復,也就是轉換或解密為通常的字符。如果解密是在輸入過濾之後,那麼攻擊者就可以通過加密來繞過這個檢查機制。例如,如果一個應用程序通過刪除用戶輸入數據中"號來防止某些SQL注入攻擊的話,由於過濾先於恢復,那麼攻擊者可以使用"號的URL加密形式%27來繞過這個檢查機制。同理,如果檢查機制也會去掉%27話,只要沒有遞歸處理,那麼%%2727就能夠得逞。

有時候避免多步檢查和恢復中存在的問題是比較困難的。不存在單一的方案能夠解決這些問題。有些情況下,遞歸地處理一個有問題的字符可能會

導致死循環,通常,這只能在所執行的檢查類型上來根據情況處理,情況允許的話,更好的方法就是簡單地拒絕某些類型的惡意輸入。

沒有留言:

張貼留言