摘要: Dino 總結了最常見的 Web 攻擊類型,并介紹了 Web 開發人員可以如何使用 ASP.NET 的內置功能來改進安全性。
一、ASP.NET 開發人員應當始終堅持的做法 如果您正在閱讀本文,可能就不需要再向您灌輸 Web 應用程序中的安全性愈來愈重要這一事實了。您需要的可能是一些有關如何在 ASP.NET 應用程序中實現安全性的實際建議。壞消息是,沒有任何開發平臺 — 包括 ASP.NET在內 — 能夠保證一旦采用了該平臺,您就能夠編寫百分百安全的代碼。誰要是這么說,一準在撒謊。好消息是,就 ASP.NET 來說,ASP.NET,特別是版本 1.1 和即將發行的版本 2.0,集成了一些便于使用的內置防御屏障。
光是應用所有這些功能并不足以保護 Web 應用程序,使其免受任何可能和可預見的攻擊。但是,如果與其他防御技巧和安全策略相結合,內置的 ASP.NET 功能將可以構成一個強大的工具包,有助于確保應用程序在安全的環境中運行。
Web 安全性是各種因素的總和,是一種范圍遠超單個應用程序的策略的結果,這種策略涉及數據庫管理、網路配置,以及社會工程和 phishing。
本文的目的在于說明 ASP.NET 開發人員為了將安全標準保持到合理的高度,所應始終堅持的做法。這也就是安全性最主要的內容:保持警惕,永不完全放松,讓壞人越來越難以發起黑客攻擊。
下面我們來看看 ASP.NET 提供了哪些可以簡化這項工作的功能。
二、威脅的來源在表 1 中,我匯總了最常見的 Web 攻擊類型,以及應用程序中可能導致這些攻擊得手的缺陷。
攻擊 攻擊的可能發起人跨站點腳本 (XSS)回顯到頁的不可信用戶輸入SQL 注入串連用戶輸入以形成 SQL 命令會話劫持會話 ID 猜測和失竊的會話 ID Cookie一次單擊通過腳本發送的未被察覺的 HTTP 張貼隱藏域篡改未檢查(且受信)的隱藏域被填充以敏感數據
表 1. 常見的 Web 攻擊
列表中顯現出來的關鍵性事實有哪些?在我看來,起碼有以下三點:
1.無論您何時將何種用戶輸入插入瀏覽器的標記中,您都潛在地將自己暴露在了代碼注入攻擊(任何 SQL 注入和 XSS 變種)之下。
?。? 必須以安全的方式實現數據庫訪問,就是說,應當為數據庫使用盡可能少的權限,并通過角色來劃分各個用戶的職責。
?。?永遠都不通過網絡發送敏感數據(更別說是明文了),并且必須以安全的方式將敏感數據存儲在服務器上。
有意思的是,上面的三點分別針對的是 Web 安全性的三個不同方面,而這三個方面結合起來,才是唯一的一種生成防攻擊、防篡改應用程序的合理方式。Web 安全性的各個層面可以總結如下:
1.編碼實踐:數據驗證、類型和緩沖區長度檢查,防篡改措施
?。?數據訪問策略:使用決策來保護可能最弱的帳戶,使用存儲過程或者至少是參數化的命令。
?。?有效的存儲和管理:不將關鍵性數據發送到客戶端,使用哈希代碼來檢測操作,對用戶進行身份驗證并保護標識,應用嚴格的密碼策略
如您所看到的,只有可以通過開發人員、架構師和管理員的共同努力,才可以產生安全的應用程序。請不要假定您能夠以其他方式達到同樣目的。
編寫 ASP.NET 應用程序時,您并不是獨自面對黑客大軍:唯一的武器是通過自己的大腦、技能和手指鍵入的代碼行。ASP.NET 1.1 和更高版本都會施加援手,它們具有一些特定的功能,可以自動提高防御以上列出的某些威脅的屏障。下面我們對它們進行詳細的檢視。
三、ViewStateUserKey 從 ASP.NET 1.1 開始引入,ViewStateUserKey 是 Page 類的一個字符串屬性,只有很少數開發人員真正熟悉該屬性。為什么呢?讓我們看看文檔中是怎么說的。
在與當前頁相關聯的視圖狀態變量中將一個標識符分配給單個用戶
除了有些累贅,這個句子的意思相當清楚;但是,您能老老實實地告訴我,它說明了該屬性原本的用途嗎?要理解 ViewStateUserKey 的角色,您需要繼續往下讀,直到 Remarks 部分。
該屬性有助于防止一次單擊攻擊,因為它提供了附加的輸入以創建防止視圖狀態被篡改的哈希值。換句話說,ViewStateUserKey 使得黑客使用客戶端視圖狀態的內容來準備針對站點的惡意張貼困難了許多??梢詾樵搶傩苑峙淙魏畏强盏淖址?,但最好是會話 ID 或用戶的 ID。為了更好地理解這個屬性的重要性,下面我們簡短介紹一下一次單擊攻擊的基本知識。
一次單擊攻擊包括將惡意的 HTTP 表單張貼到已知的、易受攻擊的 Web 站點。之所以稱為“一次單擊”,是因為它通常是以受害者不經意的單擊通過電子郵件發送的或者在擁擠的論壇中瀏覽時發現的誘惑性鏈接而開始的。通過點擊該鏈接,用戶無意中觸發了一個遠程進程,最終導致將惡意的<form>提交到一個站點。大家都坦白些吧:您真能告訴我,您從未因為好奇而單擊過 Click here to win $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 不可預測,會超時失效,并且對于每個用戶都是不同的。
以下是一些在您的所有頁中都必不可少的代碼:
void Page_Init (object sender, EventArgs e) {ViewStateUserKey = session.SessionID;:}
為了避免重復編寫這些代碼,您可以將它們固定在從 Page 派生的類的 OnInit 虛擬方法中。(請注意,您必須在 Page.Init 事件中設置此屬性。)
PRotected override OnInit(EventArgs e) {base.OnInit(e);ViewStateUserKey = Session.SessionID;}
總體說來,使用基 page 類始終都不失為一件好事,我在 Build Your ASP.NET Pages on a Richer Bedrock 一文中已經進行了說明。如果您要了解更多有關一次單擊攻擊者的伎倆的信息,可以在 aspnetpro.com 找到一篇非常好的文章。
新聞熱點
疑難解答