會話劫持
Cookie 還被用于檢索特定用戶的會話狀態。會話的 ID 被存儲到 cookie 中,該 cookie 與請求一起來回傳送,存儲在瀏覽器的計算機上。同樣,如果失竊,會話 cookie 將可被用來使黑客進入系統并訪問別人的會話狀態。不用說,只要指定的會話處于活動狀態(通常不超 20 分鐘),這就有可能發生。通過冒充的會話狀態發起的攻擊稱為會話劫持。有關會話劫持的詳細信息,請閱讀 Theft On The Web: Prevent Session Hijacking。
這種攻擊有多危險?很難講。這要取決于 Web 站點的功能,更為重要的是,該站點的頁是如何設計的。例如,假定您能夠獲得別人的會話 cookie,并將它附加到對站點上某個頁的請求中。您加載該頁并逐步研究它的普通用戶界面。除了該頁使用另一個用戶的會話狀態工作外,您無法將任何代碼注入該頁,也無法修改該頁中的任何內容。這本身并不太壞,但是如果該會話中的信息是敏感和關鍵性的,就有可能直接導致黑客成功實現利用。黑客無法滲透到會話存儲的內容中,但他可以使用其中存儲的信息,就像自己是合法進入的一樣。例如,假定有這樣一個電子商務應用程序,它的用戶在瀏覽站點時將物品添加到購物車中。
• 方案 1。 購物車的內容存儲在會話狀態中。但是,在結帳時,用戶被要求通過安全的 SSL 連接確認和輸入付款詳細信息。這種情況下,通過接入其他用戶的會話狀態,黑客僅可以了解到一些有關受害者的購物喜好的細節。在這種環境下劫持實際上并不會導致任何損害。受威脅的只是保密性。
• 方案 2。應用程序為每位注冊用戶處理一份檔案,并將檔案保存在會話狀態中。糟糕的是,檔案中(可能)包括信用卡信息。為什么要將用戶檔案詳細信息存儲到會話中?可能應用程序的其中一個目標是,從根本上避免使用戶不得不重復鍵入自己的信用卡和銀行信息。因此,在結算時,應用程序會將用戶定位到一個具有預先填充的域的頁。而有失謹慎的是,這些域的其中一個是從會話狀態中獲取的信用卡號,F在您可以猜到故事的結局了嗎?
應用程序的頁的設計,是防止會話劫持攻擊的關鍵所在。當然,還有兩點沒有理清。第一點是,如何防止 cookie 盜竊?第二點是,ASP.NET 可以如何檢測和阻止劫持?
ASP.NET 會話 cookie 極其簡單,僅限于包含會話 ID 字符串本身。ASP.NET 運行庫從 cookie 中提取會話 ID,并將其與活動的會話進行比較。如果 ID 有效,ASP.NET 將連接到對應的會話并繼續。這種行為極大地方便了已經偷到或者可以猜出有效的會話 ID 的黑客。
XSS 和中間人 (man-in-the-middle) 攻擊以及對客戶端 PC 的強力訪問,都是獲取有效 cookie 的方法。為了防止盜竊,您應當實現安全最佳實踐來防止 XSS 及其各變種得手。
而為了防止會話 ID 猜測,您應當干脆避免太高估計自己的技能。猜測會話 ID 意味著您知道如何預測有效的會話 ID 字符串。對于 ASP.NET 所使用的算法(15 個隨機數字,映射為啟用 URL 的字符),隨機猜測到有效 ID 的概率接近于零。我想不到任何理由來用自己的會話 ID 生成器替換默認的會話 ID 生成器。許多情況下,這么做只會為攻擊者提供方便。
會話劫持更為糟糕的后果是一旦 cookie 被盜或者被猜出,ASP.NET 并沒有什么辦法來檢測欺詐性的 cookie 使用。同樣,原因是 ASP.NET 將自己限制為檢查 ID 的有效性,以及 cookie 的來源地。
我在 Wintellect 的朋友 Jeff Prosise 為 MSDN Magazine 寫了一篇很好的關于會話劫持的文章。他的結論并不令人安慰:幾乎不可能建立能夠完全抵御依靠偷來的會話 ID Cookie 所發起的攻擊的防御工事。但是他開發的代碼為進一步提升安全標準提供了非常明智的建議。Jeff 創建了一個 HTTP 模塊,該模塊為會話 ID Cookie 監視傳入的請求和傳出的響應。該模塊將一條哈希代碼附加到會話 ID 之后,使攻擊者重用 cookie 更為困難。您可以在此處閱讀詳情。
EnableViewStateMac
視圖狀態用于在對同一個頁的兩個連續請求之間保持控件的狀態。默認情況下,視圖狀態是 Base64 編碼的,并使用一個哈希值簽名,以防止篡改。除非更改默認的頁設置,否則不可能篡改視圖狀態。如果攻擊者修改了視圖狀態,甚至使用正確的算法重新生成了視圖狀態,ASP.NET 都會捕獲這些嘗試并引發異常。視圖狀態被篡改并不一定有害,雖然它修改了服務器控件的狀態 — 但可能成為造成嚴重感染的工具。因此,不 移除默認情況下進行的計算機身份驗證代碼 (MAC) 交叉檢查就異常重要。請參閱圖 2。

圖 2. 啟用 EnableViewStateMac 時,使視圖狀態本身難以篡改的因素
啟用了 MAC 檢查時(默認情況),將對序列化的視圖狀態附加一個哈希值,該值是使用某些服務器端值和視圖狀態用戶秘鑰(如果有)生成的;匕l視圖狀態時,將使用新的服務器端值重新計算該哈希值,并將其與存儲的值進行比較。如果兩者匹配,則允許請求;否則將引發異常。即使假設黑客具有破解和重新生成視圖狀態的能力,他/她仍需要知道服務器存儲的值才可以得出有效的哈希。具體說來,該黑客需要知道 machine.config 的 machineKey 項中引用的計算機秘鑰。
默認情況下, 項是自動生成的,以物理方式存儲在 Windows Local Security Authority (LSA) 中。僅在 Web 場(此時視圖狀態的計算機秘鑰必須在所有的計算機上都相同)的情形下,您才應當在 machine.config 文件中將其指定為明文。
視圖狀態 MAC 檢查是通過一個名為 EnableViewStateMac 的 @Page 指令屬性控制的。如前所述,默認情況下,它被設置為 true。請永遠不要禁用它;否則將會使視圖狀態篡改一次單擊攻擊成為可能,并具有很高的成功概率。
ValidateRequest
跨站點腳本 (XSS) 對于很多經驗豐富的 Web 開發人員來說是老朋友了,它在 1999 年左右就已經出現了。簡單地說,XSS 利用代碼中的漏洞來將黑客的可執行代碼引入另一個用戶的瀏覽器會話中。如果被執行,注入的代碼可以執行多種不同的操作 — 獲取 Cookie 并將一個副本上載到黑客控制的 Web 站點,監視用戶的 Web 會話并轉發數據,修改被黑的頁的行為和外觀以使其提供錯誤的信息,甚至使自己變為持續性的,這樣用戶下一次返回該頁時,欺詐代碼會再次運行。請在 TechNet 文章 Cross-site Scripting Overview 中詳細閱讀有關 XSS 攻擊的基礎知識。
代碼中的哪些漏洞導致 XSS 攻擊成為可能?
XSS 利用的是動態生成 HTML 頁、但并不驗證回顯到頁的輸入的 Web 應用程序。這里的輸入 是指查詢字符串、Cookie 和表單域的內容。如果這些內容在未經適當性能檢查的情況下出現在網絡上,就存在黑客對其進行操作以在客戶端瀏覽器中執行惡意腳本的風險。(前面提到的一次單擊攻擊其實是 XSS 的一種新近變種。)典型的 XSS 攻擊會導致不抱懷疑的用戶點擊一條誘惑性鏈接,而該鏈接中嵌入了轉義的腳本代碼。欺詐代碼將被發送到一個存在漏洞且會毫不懷疑地輸出它的頁。以下是可能發生的情況的一個示例:
<a href="http://www.vulnerableserver.com/brokenpage.aspx?Name= |
用戶單擊一個看上去明顯安全的鏈接,最終導致將一些腳本代碼傳遞到存在漏洞的頁,這些代碼首先獲取用戶計算機上的所有 Cookie,然后將它們發送到黑客的 Web 站點。
請務必注意,XSS 不是一個特定于供應商的問題,因此并不一定會利用 Internet Explorer 中的漏洞。它影響目前市場上的所有 Web 服務器和瀏覽器。更應注意的是,沒有哪一個修補程序能夠修復這一問題。您完全可以保護自己的頁免受 XSS 攻擊,方法是應用特定的措施和合理的編碼實踐。此外,請注意,攻擊者并不需要用戶單擊鏈接就可以發起攻擊。
要防御 XSS,您必須從根本上確定哪些輸入是有效的,然后拒絕所有其他輸入。您可以在一本書中讀到抵御 XSS 攻擊的詳細檢查表,該書在 Microsoft 屬于必讀范圍 — Writing Secure Code,作者是 Michael Howard 和 David LeBlanc。特別地,我建議您仔細閱讀第 13 章。
阻止陰險的 XSS 攻擊的主要方法是向您的輸入(任何類型的輸入數據)添加一個設計合理、有效的驗證層。例如,某些情況下即使是原本無害的顏色(RGB 三色)也會將不受控制的腳本直接帶入頁中。
在 ASP.NET 1.1 中,@Page 指令上的 ValidateRequest 屬性被打開后,將檢查以確定用戶沒有在查詢字符串、Cookie 或表單域中發送有潛在危險性的 HTML 標記。如果檢測到這種情況,將引發異常并中止該請求。該屬性默認情況下是打開的;您無需進行任何操作就可以得到保護。如果您想允許 HTML 標記通過,必須主動禁用該屬性。
<%@ Page ValidateRequest="false" %> |
ValidateRequest不是 萬能的藥方,無法替代有效的驗證層。請閱讀此處以獲取大量有關該功能的基礎原理的寶貴信息。它基本上通過應用一個正則表達式來捕獲一些可能有害的序列。
注 ValidateRequest 功能原本是有缺陷的,因此您需要應用一個修補程序它才能按預期工作。這樣的重要信息常常不為人們所注意。奇怪的是,我發現我的其中一臺計算機仍受該缺陷的影響。試試看!
沒有任何關閉 ValidateRequest 的理由。您可以禁用它,但必須有非常好的理由;其中一條這樣的理由可能是用戶需要能夠將某些 HTML 張貼到站點,以便得到更好的格式設置選項。這種情況下,您應當限制所允許的 HTML 標記(<pre>、<b>、<i>、<p>、<br>、<hr>)的數目,并編寫一個正則表達式,以確保不會允許或接受任何其他內容。
以下是一些有助于防止 ASP.NET 遭受 XSS 攻擊的其他提示:
• 使用 HttpUtility.HtmlEncode 將危險的符號轉換為它們的 HTML 表示形式。
• 使用雙引號而不是單引號,這是因為 HTML 編碼僅轉義雙引號。
• 強制一個代碼頁以限制可以使用的字符數。
總之,使用但是不要完全信任 ValidateRequest 屬性,不要太過懶惰;ㄐ⿻r間,從根本上理解 XSS 這樣的安全威脅,并規劃以一個關鍵點為中心的防御策略:所有的用戶輸入都是危險的。
數據庫角度
SQL 注入是另一種廣為人知的攻擊類型,它利用的是使用未篩選的用戶輸入來形成數據庫命令的應用程序。如果應用程序興高采烈地使用用戶鍵入表單域中的內容來創建 SQL 命令字符串,就會將您暴露在這一風險下:惡意用戶只需訪問該頁并輸入欺詐參數,就可以修改查詢的性質。您可以在此處了解更多有關 SQL 注入的信息。
要阻止 SQL 注入攻擊,有許多方法。以下介紹最常見的技巧。
• 確保用戶輸入屬于適當的類型,并遵循預期的模式(郵政編碼、身份證號,電子郵件等)。如果預期來自文本框的數字,請在用戶輸入無法轉換為數字的內容時阻止該請求。
• 使用參數化的查詢,使用存儲過程更好。
• 使用 SQL Server 權限來限制各個用戶可以對數據庫執行的操作。例如,您可能需要禁用 xp_cmdshell 或者將該操作的權限僅限于管理員。
如果使用存儲過程,可以顯著降低發生這種攻擊的可能性。實際上,有了存儲過程,您就無需動態地撰寫 SQL 字符串。此外,SQL Server 中將驗證所有參數是否具有指定的類型。雖然光是這些并不是百分百安全的技巧,但是加上驗證的話,將足以提高安全性。
更為重要的是,應確保只有經過授權的用戶才能夠執行可能具有嚴重后果的操作,如刪除表。這要求認真仔細地設計應用程序的中間層。好的技巧(不光是為了安全性)應把焦點集中在角色上。應當將用戶分組為各種角色,并為各個角色定義一個包含一組最少的權限的帳戶。
幾周前,Wintellect Web 站點受到一種很復雜的 SQL 注入的攻擊。那位黑客試圖創建并啟動一個 FTP 腳本來下載一個可能是惡意的可執行程序。幸運的是,這次攻擊失敗了;蛘,其實是強用戶驗證,使用存儲過程和使用 SQL Server 權限,導致了攻擊未能成功?
總而言之,您應當遵循這些指南,以避免被注入有害的 SQL 代碼:
• 使用盡可能少的權限運行,永遠不以“sa”身份執行代碼。
• 將訪問限制給內置的存儲過程。
• 首選使用 SQL 參數化查詢。
• 不通過字符串串連來生成語句,不回顯數據庫錯誤。
隱藏域
在傳統的 ASP 中,隱藏域是唯一一種在請求之間保持數據的方法。您需要在下一個請求中檢索的任何數據都被打包到隱藏的 <input> 域中,并執行回程。如果有人在客戶端上修改了該域中存儲的值,會怎樣?只要文本是明文的,服務器端環境就無法測知這一情況。ASP.NET 中,頁和各個控件的 ViewState 屬性有兩個用途。一方面,ViewState 是跨請求保持狀態的方法;另一方面,ViewState 使您能夠在受保護的、不易篡改的隱藏域中存儲自定義值。
視圖狀態被附加了一個哈希值,對于每條請求,都會檢查該值,以檢測是否發生了篡改。除少數幾種情況外,沒有任何理由要在 ASP.NET 中使用隱藏域。視圖狀態能夠以安全得多的方式實現相同的功能。前面開門見山地講到過,在明文的隱藏域中存儲敏感的值(如價格或信用卡詳細信息),相當于對黑客張開大門;視圖狀態甚至能夠使這種不好的做法比以前更為安全,因為視圖狀態具有數據保護機制。但是,請牢記,視圖狀態可以防止篡改,但是并不能保證保密性,除非使用加密 — 存儲在視圖狀態中的信用卡詳細信息無論如何都有風險。
在 ASP.NET 中,哪些情況下使用隱藏域是可接受的?當您生成需要將數據發送回服務器的自定義控件時。例如,假定您要創建一個支持重派列順序的新 DataGrid 控件。您需要在回發中將新的順序發送回服務器。如果不將這些信息存儲到隱藏域中,又可以存儲到哪里?
如果隱藏域為讀/寫域,即預期客戶端會寫入它,沒什么辦法能夠完全制止黑客攻擊。您可以嘗試哈;蛘呒用茉撐谋,但這并不能讓您合理地確信不會遭受黑客攻擊。此時,最好的防御就是讓隱藏域包含惰性和無害的信息。
此外,應當注意 ASP.NET 公開了一個鮮為人知的類,可用于編碼和哈希任何序列化的對象.該類為 LosFormatter,ViewState 實現用于創建回程到客戶端的編碼文本正是同一個類。
private string EncodeText(string text) { |
前面的代碼片段演示了如何使用 LosFormatter 來創建類似視圖狀態的內容,對其編碼并進行哈希。
電子郵件和垃圾郵件
在本文結尾,請讓我指出,最常見的攻擊中至少有兩種(經典的 XSS 和一次單擊)通常是通過誘使不抱懷疑的受害者單擊誘惑性和欺騙性的鏈接來發起的。很多時候我們都可以在自己的收件箱中發現這樣的鏈接,雖然有反垃圾郵件過濾器。幾美元就可以買到大量電子郵件地址。用來生成這種列表的其中一種主要的技巧就是掃描 Web 站點上的公共頁,查找并獲取所有看上去像電子郵件的內容。
如果頁上顯示了電子郵件地址,很可能或早或晚這個地址都會被自動 Web 程序捕獲。真的嗎?當然,這要看該電子郵件是如何顯示的。如果硬編碼它,您輸定了。如果采用其他表示形式(如 dino-at-microsoft-dot-com),是否能夠騙過自動 Web 程序不太清楚,但能讓所有閱讀您的頁并想建立合法聯系的人光火,倒是一定的。
總體說來,您應當確定一種方法,將電子郵件動態地生成為 mailto 鏈接。Marco Bellinaso 編寫的一個免費組件恰好可以完成這項工作。您可以從 DotNet2TheMax Web 站點獲得該組件的全部源代碼。
小結
有人懷疑 Web 可能是所有運行時環境中敵意最盛的嗎?根源在于誰都可以訪問 Web 站點,并嘗試向它傳遞好的或壞的數據。但是,創建不接受用戶輸入的 Web 應用程序,又有什么意義呢?
我們還是直面現實吧:無論您的防火墻如何強大,無論您如何頻繁地應用可用的修補程序,只要您運行的 Web 應用程序先天包含缺陷,攻擊者遲早都可以通過主通道,也就是端口 80,直接進入您的系統的最核心部分。
ASP.NET 應用程序與其他 Web 應用程序相較,既不更易受攻擊,也不更安全。安全性和漏洞同樣根植于編碼實踐、實際經驗和團隊合作。如果網絡不安全,那么任何應用程序都不安全;類似地,無論網絡如何安全,管理如何精良,如果應用程序存在缺陷,攻擊者總是能夠得手。
ASP.NET 的好處是提供了一些好的工具,只需少量工作,就可以將安全標準提升到可以接受的級別。當然,這并不是 足夠高的級別。不應純粹以來 ASP.NET 的內置解決方案,同樣也不應忽視它們。盡可能多地了解常見的攻擊。
本文提供了內置功能的帶注釋的列表,以及一些有關攻擊與防御的背景知識。用來檢測傳出的攻擊的技巧是另一回事,可能需要一篇專門的文章來進行介紹。
