构建安全的 ASP.NET 网页和控件
本頁內容
| 本模塊內容 | |
| 目標 | |
| 適用范圍 | |
| 如何使用本模塊 | |
| 威脅和對策 | |
| 設計注意事項 | |
| 輸入驗證 | |
| 跨站點腳本 | |
| 身份驗證 | |
| 授權 | |
| 模擬 | |
| 敏感數(shù)據(jù) | |
| 會話管理 | |
| 參數(shù)處理 | |
| 異常管理 | |
| 審核和日志記錄 | |
| 小結 | |
| 其他資源 |
本模塊內容
Web 頁和控件位于應用程序的防御前線,它們很容易受到蓄意破壞應用程序安全的攻擊者的猛烈攻擊。攻擊者的最終目標一般是后端系統(tǒng)和數(shù)據(jù)存儲。
像代碼注入或跨站點腳本 (XSS) 這些成功的應用程序攻擊都利用了服務器端應用程序漏洞。這些漏洞可造成破壞性的影響,并導致信息曝光、身份哄騙、權限提升及遠程執(zhí)行代碼。要構建安全的 Web 頁和控件,您必須遵照本模塊討論的正確編程方法。
模塊首先列出并說明了常見的 ASP.NET 頁和控件威脅及其相關對策,然后提供了一份必須解決的應用程序安全問題綜合列表。表中包括了輸入驗證、輸出編碼、身份驗證、授權、模擬、敏感數(shù)據(jù)保護、安全會話管理、參數(shù)處理保護和異常管理。這些技術都是深層安全解決方案的基本組成部分。但由于上述威脅常被忽視,無論基礎結構如何安全,攻擊者都能成功破壞您的系統(tǒng)。
返回頁首目標
使用本模塊可以實現(xiàn):
| ? | 設計安全的 ASP.NET 頁和控件。 |
| ? | 使用正則表達式和其他技術開發(fā)安全的驗證代碼。 |
| ? | 防止跨站點腳本 (XSS)。 |
| ? | 驗證用戶身份并授權。 |
| ? | 開發(fā)安全的表單身份驗證。 |
| ? | 防止大量異常細節(jié)信息送達客戶端。 |
| ? | 管理和保護 ASP.NET 會話。 |
| ? | 禁止處理參數(shù)。 |
| ? | 了解哪些對策適用于解決常見的威脅,包括代碼注入、會話劫持、身份哄騙、參數(shù)處理、網(wǎng)絡竊聽、信息曝光、跨站點腳本 (XSS) 和 cookie 重播攻擊。 |
適用范圍
本模塊適用于下列產(chǎn)品和技術:
| ? | Microsoft? Windows? 2000 Server 和 Microsoft Windows Server? 2003 |
| ? | Microsoft .NET Framework 1.1 和 ASP.NET 1.1 |
如何使用本模塊
除了后面介紹的安全編程方法之外,您還可以使用本指南的相應模塊來輔助構建安全的 ASP.NET 網(wǎng)頁和控件。
| ? | 執(zhí)行模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全中的步驟。該模塊可幫助您使用 Machine.config 和 Web.config 中的安全設置配置 ASP.NET。 |
| ? | 使用本指南檢查表部分附帶的檢查表。檢查表:保護 ASP.NET 的安全將本模塊提供的建議與模塊 19 提供的建議結合在一起。請確保實施這里的指南。 |
| ? | 了解特定于 ASP.NET 頁和控件的威脅和攻擊。根據(jù)本模塊的指導采取相應對策。 |
| ? | 閱讀模塊 4 Web 應用程序安全設計指南。本模塊(模塊 10)的很多建議都基于模塊 4 討論的設計指導原則。 |
| ? | 設計人員應使用本模塊的設計注意事項部分。 |
| ? | 開發(fā)人員應將本模塊中的指導原則應用于開發(fā)過程。開發(fā)人員必須特別注意對輸入數(shù)據(jù)的驗證工作,如果該環(huán)節(jié)有安全漏洞,大部分高端應用程序級攻擊便有機可乘。 |
| ? | 請從編程角度了解控件,以便進一步控制 ASP.NET 頁和控件的安全性。 |
| ? | 使用應用程序安全漏洞類別來處理常見的問題。應用程序安全漏洞類別是處理和分組問題的一種有效方法。 |
威脅和對策
大多數(shù) Web 應用程序攻擊都要在 HTTP 請求中傳遞惡意輸入項。一般,這種攻擊并非強迫應用程序執(zhí)行未經(jīng)授權的操作,而是要中斷應用程序的正常操作。因此,全面驗證輸入內容是解決很多攻擊的必要步驟。而且,在您開發(fā) ASP.NET Web 頁和控件時,必須賦予輸入驗證最高的優(yōu)先級。常見威脅包括:
| ? | 代碼注入 |
| ? | 會話劫持 |
| ? | 身份哄騙 |
| ? | 參數(shù)處理 |
| ? | 網(wǎng)絡竊聽 |
| ? | 信息泄漏 |
圖 10.1 著重介紹了 Web 應用程序面臨的常見威脅。
圖 10.1
“ASP.NET Web 頁和控件的常見威脅”
代碼注入
如果攻擊者使用您應用程序的安全上下文運行任意代碼,則產(chǎn)生代碼注入攻擊。如果應用程序使用特權帳戶運行,將增加系統(tǒng)受攻擊的風險。
攻擊
代碼注入攻擊有很多類型,具體包括:
| ? | 跨站點腳本:將惡意腳本作為輸入項發(fā)送到 Web 應用程序。一旦執(zhí)行,結果將回應至用戶瀏覽器。 |
| ? | 緩沖區(qū)溢出:雖然托管代碼的類型安全驗證可大大降低風險,但應用程序依然存在安全漏洞,特別是調用非托管代碼時。緩沖區(qū)溢出使攻擊者可利用 Web 應用程序的安全上下文在 Web 應用程序進程中執(zhí)行任意代碼。 |
| ? | SQL 注入:攻擊對象是存在安全漏洞的數(shù)據(jù)訪問代碼。攻擊者可發(fā)送 SQL 輸入來更改數(shù)據(jù)庫中的預期查詢或執(zhí)行全新的查詢。表單身份驗證登錄頁是常見的攻擊對象,因為查詢用戶存儲所使用的是用戶名和密碼。 |
安全漏洞
導致代碼注入攻擊成功的安全漏洞包括:
| ? | 輸入驗證薄弱或缺失,或依賴客戶端的輸入驗證 |
| ? | HTML 輸出中包括未經(jīng)驗證的輸入 |
| ? | 動態(tài)構建的 SQL 語句未使用鍵入的參數(shù) |
| ? | 使用超越特權的進程帳戶和數(shù)據(jù)庫登錄 |
對策
防止代碼注入可采取下列對策:
| ? | 驗證輸入,使攻擊者無法注入腳本代碼或使緩沖區(qū)溢出。 |
| ? | 對所有包含輸入的輸出進行編碼。這可防止客戶端瀏覽器將潛在的惡意腳本標記作為代碼進行轉換。 |
| ? | 使用接受參數(shù)的存儲過程,防止數(shù)據(jù)庫將惡意 SQL 輸入作為可執(zhí)行語句進行處理。 |
| ? | 使用特權最低的進程帳戶和模擬帳戶。如果攻擊者企圖利用應用程序的安全上下文執(zhí)行代碼,這可緩解風險并減少損害。 |
會話劫持
如果攻擊者捕獲了身份驗證令牌并控制了其他用戶的會話,則發(fā)生會話劫持現(xiàn)象。通常,身份驗證令牌保存在 cookie 或 URL 中。如果攻擊者捕獲了身份驗證令牌,他(或她)會將令牌連同請求一起傳遞給應用程序。應用程序則將該請求與合法用戶會話相關聯(lián),這樣,攻擊者便得到了訪問該應用程序受限內容(這些受限內容都要求驗證訪問身份)的權限。進而,攻擊者便有了合法的用戶身份和權限。
安全漏洞
致使 Web 頁和控件遭受會話劫持攻擊的常見安全漏洞包括:
| ? | URL 中的會話標識符未受保護 |
| ? | 混用個性化 cookie 與身份驗證 cookie |
| ? | 身份驗證 cookie 通過未經(jīng)加密的鏈接傳遞 |
攻擊
會話劫持攻擊包括:
| ? | Cookie 重播:攻擊者可以使用網(wǎng)絡監(jiān)視軟件或其他方法(例如,利用 XSS 腳本的安全漏洞)捕獲身份驗證 cookie。 |
| ? | 查詢字符串處理:惡意用戶可更改在 URL 查詢字符串中顯而易見的會話標識符。 |
對策
可采取下列對策防止會話劫持:
| ? | 分隔個性化 cookie 和身份驗證 cookie。 |
| ? | 僅通過 HTTPS 連接傳遞身份驗證 cookie。 |
| ? | 不傳遞在查詢字符串中代表已通過身份驗證的用戶會話標識符。 |
| ? | 執(zhí)行重要操作(如下訂單、現(xiàn)金轉移等)前重新驗證用戶。 |
身份哄騙
如果惡意用戶盜用合法用戶的身份訪問應用程序,則發(fā)生身份哄騙現(xiàn)象。
安全漏洞
致使 Web 頁和控件遭受身份哄騙攻擊的常見安全漏洞包括:
| ? | 身份驗證憑據(jù)通過未經(jīng)加密的鏈接傳遞 |
| ? | 身份驗證 cookie 通過未經(jīng)加密的鏈接傳遞 |
| ? | 密碼和策略薄弱 |
| ? | 用戶存儲中的憑據(jù)存儲較薄弱 |
攻擊
身份哄騙攻擊包括:
| ? | Cookie 重播:攻擊者可以使用網(wǎng)絡監(jiān)視軟件或通過 XSS 攻擊竊取身份驗證 cookie。然后,再將該 cookie 發(fā)送給應用程序以騙取訪問權限。 |
| ? | 強力密碼攻擊:攻擊者不斷嘗試各種用戶名和密碼組合。 |
| ? | 字典攻擊:在自動強力密碼攻擊中,攻擊者可將字典中的每個詞作為密碼。 |
對策
可采取下列對策防止身份哄騙:
| ? | 僅通過 HTTPS 連接傳遞身份驗證憑據(jù)和身份驗證 cookie。 |
| ? | 強制使用強密碼。可使用正則表達式確保用戶提供的密碼符合一定的復雜性要求。 |
| ? | 將密碼驗證程序保存在數(shù)據(jù)庫中。將不可逆的密碼哈希值與隨機 salt 值結合在一起保存,以降低字典攻擊的風險。 |
有關在數(shù)據(jù)庫中保存密碼哈希值和其他機密的詳細信息,請參閱模塊 14 構建安全的數(shù)據(jù)訪問。
參數(shù)處理
參數(shù)是網(wǎng)絡中從客戶端傳遞至服務器的一些數(shù)據(jù)。參數(shù)包括表單域、查詢字符串、視圖狀態(tài)、cookie 和 HTTP 頭。如果使用未經(jīng)保護的參數(shù)傳遞敏感數(shù)據(jù)(或傳遞用于制定服務器安全決策的數(shù)據(jù)),應用程序可能有信息泄漏的危險,或遭受未授權的訪問。
安全漏洞
可導致參數(shù)處理的安全漏洞包括:
| ? | 使用含敏感數(shù)據(jù)的隱藏表單域或查詢字符串 |
| ? | 通過未經(jīng)加密的連接傳遞含安全敏感數(shù)據(jù)的 cookie |
攻擊
參數(shù)處理攻擊包括:
| ? | Cookie 重播攻擊:攻擊者捕獲并改變了 cookie,然后在應用程序中重播。如果 cookie 中包含的數(shù)據(jù)用于在服務器中進行身份驗證或授權,很容易導致身份哄騙和權限提升。 |
| ? | 處理隱藏表單域:這些域包含了在服務器中制定安全決策要用的數(shù)據(jù)。 |
| ? | 處理查詢字符串參數(shù) |
對策
可采取下列對策防止參數(shù)處理:
| ? | 不依賴于客戶端狀態(tài)管理選項。避免使用任何客戶端狀態(tài)管理選項保存敏感數(shù)據(jù)。這些選項包括:視圖狀態(tài)、cookie、查詢字符串或隱藏表單域。 |
| ? | 在服務器中保存敏感數(shù)據(jù)。使用會話令牌將用戶會話與服務器中維護的敏感數(shù)據(jù)項相關聯(lián)。 |
| ? | 使用消息身份驗證代碼 (MAC) 保護會話令牌。將令牌與服務器中相應的身份驗證、授權和業(yè)務邏輯相匹配,確保令牌不處于重播狀態(tài)。 |
網(wǎng)絡竊聽
網(wǎng)絡竊聽涉及使用網(wǎng)絡監(jiān)視軟件跟蹤傳遞于瀏覽器和 Web 服務器之間的數(shù)據(jù)包。它可導致泄漏應用程序特定的機密數(shù)據(jù)、檢索登錄憑據(jù)或捕獲身份驗證 cookie。
安全漏洞
可導致網(wǎng)絡竊聽攻擊成功的安全漏洞包括:
| ? | 發(fā)送敏感數(shù)據(jù)時未加密 |
| ? | 通過未經(jīng)加密的通道發(fā)送身份驗證 cookie |
攻擊
使用網(wǎng)絡中的數(shù)據(jù)包嗅探 (sniff) 工具可實施網(wǎng)絡竊聽攻擊,從而捕獲網(wǎng)絡數(shù)據(jù)流。
對策
要對抗網(wǎng)絡竊聽,請使用安全套接字層 (SSL) 在瀏覽器和 Web 服務器間建立加密通信通道。只要在網(wǎng)絡中發(fā)送憑據(jù)、身份驗證票證或敏感的應用程序數(shù)據(jù),就一定要使用 SSL。
信息泄漏
如果攻擊者通過探測 Web 頁來找尋引起異常的各種情況,則出現(xiàn)消息泄漏攻擊。對于攻擊者而言,這是一種頗有成效的攻擊方法。因為異常細節(jié)信息常以 HTML 的形式返回并顯示在瀏覽器中。這可能會泄漏很有用的信息,如堆棧跟蹤。堆棧跟蹤包含數(shù)據(jù)庫連接字符串、數(shù)據(jù)庫名、數(shù)據(jù)庫方案信息、SQL 語句以及操作系統(tǒng)和平臺版本。
安全漏洞
可導致信息泄漏的安全漏洞包括:
| ? | 異常處理能力薄弱 |
| ? | 原始的例外細節(jié)信息被傳播至客戶端 |
攻擊
可導致信息泄漏的攻擊有多種,具體包括:
| ? | 緩沖區(qū)溢出。 |
| ? | 有意發(fā)送格式錯誤的輸入。 |
對策
可采取下列措施防止信息泄漏:
| ? | 使用結構化異常處理。 |
| ? | 將一般錯誤頁返回客戶端。 |
| ? | 使用包含一般錯誤和無害錯誤消息的默認重定向頁。 |
設計注意事項
開發(fā) Web 頁和控件之前,必須考慮很多重要問題。關鍵的注意事項如下:
| ? | 使用服務器端輸入驗證。 |
| ? | 對 Web 站點進行分區(qū)。 |
| ? | 考慮訪問資源的身份。 |
| ? | 保護憑據(jù)和身份驗證票證。 |
| ? | 安全地失敗。 |
| ? | 考慮授權粒度。 |
| ? | 將 Web 控件和用戶控件置于獨立的程序集中。 |
| ? | 將資源訪問代碼置于獨立的程序集中。 |
使用服務器端輸入驗證
在設計時,請明確 Web 頁和控件所處理的全部不同用戶輸入源。包括表單域、查詢字符串、從 Web 用戶處收到的 cookie 以及來自后端數(shù)據(jù)源的數(shù)據(jù)。很顯然,Web 用戶并不屬于應用程序信任范疇,因此,您必須在服務器中驗證來自該數(shù)據(jù)源的所有輸入。除非絕對信任從后端數(shù)據(jù)源中檢索的數(shù)據(jù),否則請務必在將數(shù)據(jù)發(fā)送到客戶端之前進行驗證和凈化。確保解決方案不依賴于客戶端驗證,因為客戶端驗證很容易被忽視。
對 Web 站點進行分區(qū)
Web 站點的設計必須區(qū)分公共訪問部分和要求身份驗證的受限部分。使用應用程序虛擬根目錄下獨立的子目錄可維護各種受限的頁面。例如,典型電子商務網(wǎng)站中的結帳功能要求驗證訪問者的身份來傳遞信用卡號等敏感數(shù)據(jù)。獨立的子目錄允許您應用附加的安全性(例如,通過要求 SSL),但不會給整個站點帶來 SSL 性能負荷此外,它還允許您限制 HTTPS 連接中的身份驗證 cookie 傳遞來緩解會話劫持風險。圖 10.2 顯示了一種典型的分區(qū)。
圖 10.2
劃分為公共區(qū)域和安全區(qū)域的 Web 站點
請注意,在圖 10.2 中,受限的子文件夾使用 Internet 信息服務 (IIS) 配置,要求通過 SSL 訪問。Web.config 中的第一個 <authorization> 元素允許所有用戶訪問公共區(qū)域,第二個元素禁止未經(jīng)授權的用戶訪問安全子文件夾的內容并強制登錄。
有關限制身份驗證 cookie,使其只能通過 HTTPS 連接傳遞的詳細信息,以及如何在受限和非受限頁面間導航的詳細信息,請參閱本模塊身份驗證部分的“使用絕對 URL 導航”。
考慮訪問資源的身份
在默認情況下,ASP.NET 應用程序不模擬帳戶,而是使用特權最低的 ASPNET 進程帳戶運行 ASP.NET Web 應用程序來訪問資源。默認值是使用推薦的配置。在很多情況下,您可能需要使用不同的 Windows 安全上下文訪問資源,具體情況包括:
| ? | 在同一服務器中駐留多個應用程序 |
| ? | 訪問有特定身份驗證要求的遠程資源 |
保護憑據(jù)和身份驗證票證
您的設計必須考慮保護憑據(jù)和身份驗證票證安全的方面。如果憑據(jù)是通過網(wǎng)絡傳遞的,且位于永久存儲(如配置文件)中,您必須保護這些憑據(jù)。由于身份驗證票證容易遭受劫持攻擊,必須確保票證在網(wǎng)絡中的安全。加密即是一種解決方案。此外,您還可以使用 SSL 或 IPSec 來保護網(wǎng)絡中的憑據(jù)和身份驗證票證。DPAPI 是一種在配置文件中加密憑據(jù)的很好的解決方案。
安全地失敗
如果應用程序出現(xiàn)難以恢復的異常情況,請確保應用程序安全地失敗,不要造成系統(tǒng)完全對外部敞開的局面。防止對惡意用戶而言重要的異常細節(jié)信息被傳播給客戶端,確保僅返回一般錯誤頁。規(guī)劃使用結構化的異常處理來處理錯誤,而不是依賴方法錯誤代碼來處理錯誤。
考慮授權粒度
考慮您在站點身份驗證中使用的授權粒度。如果目錄的配置要求身份驗證,是否所有的用戶都有相等的權限來訪問該目錄中的頁面?如果需要,可基于身份(或常用的調用者角色成員身份)為不同頁面應用不同的授權規(guī)則。方法是,在不同的 <location> 元素中使用 <authorization> 元素。
例如,同一目錄中的兩個頁面在 Web.config 文件中有不同的 <allow> 元素和 <deny> 元素。
將 Web 控件和用戶控件置于獨立的程序集中
如果將 Web 控件和用戶控件置于各自的程序集中,可通過代碼訪問安全策略分別配置每個程序集的安全性。這為管理員提供了更多的靈活性。換言之,您不必僅為滿足單個控件的需要而向所有控件授予擴展權限。
將資源訪問代碼置于獨立的程序集中
使用獨立的程序集,然后根據(jù)頁類(非頁類事件處理程序中的嵌入資源訪問代碼)來調用這些程序集。這可提升代碼訪問安全策略的靈活性,并對構建部分信任 Web 應用程序起著特別重要的作用。有關詳細信息,請參閱模塊 9 ASP.NET 代碼訪問安全性。
返回頁首輸入驗證
如果對輸入的類型、長度、格式和范圍做出毫無根據(jù)的假設,應用程序可能失敗。如果攻擊者發(fā)現(xiàn)了您做出的毫無根據(jù)的假設,輸入驗證可能成為安全問題。此時,攻擊者可能提供構思巧妙的輸入,使您的應用程序受到一定的損害。在 Web 應用程序中,誤信用戶輸入是最常見且最具破壞性的安全漏洞之一。
約束并凈化
首先是限制輸入內容,然后通過驗證輸入的類型、長度、格式和范圍檢查正確數(shù)據(jù)。有時,您可能還必須凈化輸入,從而確保可能的惡意輸入的安全。例如,如果應用程序支持任意格式的輸入字段(如注釋字段),您可能要使用一些“安全”HTML 元素,如 <b> 和 <i>,然后放棄其他所有 HTML 元素。下表匯總了在約束和凈化數(shù)據(jù)中可用的選項:
表 10.1:約束和凈化數(shù)據(jù)的相關選項
| 要求 | 選項 |
| 類型檢查 | .NET Framework 類型系統(tǒng)。分析字符串數(shù)據(jù)并轉換成強類型,然后處理 FormatExceptions。 |
| 長度檢查 | 正則表達式 |
| 格式檢查 | 用于模式匹配的正則表達式 |
| 范圍檢查 | ASP.NET 的 RangeValidator 控件(支持貨幣、日期、整數(shù)、雙字節(jié)和字符串數(shù)據(jù)) |
正則表達式
您可以使用正則表達式限制有效字符的范圍、放棄無用字符或執(zhí)行長度和格式檢查。您可以定義輸入項必須匹配的模式來限制輸入格式。ASP.NET 提供了 RegularExpressionValidator 控件,而 Regex 類位于 System.Text.RegularExpressions 命名空間。
如果使用驗證程序控件,驗證將在控件為空時成功。對于必填字段,請使用 RequiredFieldValidator。此外,客戶端和服務器中實施的正則表達式驗證可能略有不同。客戶端使用的是 Microsoft Jscript 開發(fā)軟件的正則表達式語法;而服務器使用的是 System.Text.RegularExpressions.Regex 語法。由于 JScript 正則表達式語法是 System.Text.RegularExpressions.Regex 語法的子集,因此建議使用 JScript 正則表達式語法,以便在客戶端和服務器得到相同的結果。
有關 ASP.NET 驗證程序控件的完整信息,請參閱 .NET Framework 文檔。
RegularExpressionValidator 控件
要驗證 Web 表單域的輸入,您可以使用 RegularExpressionValidator 控件。請將該控件拖到 Web 表單中,然后設置 ValidationExpression、ControlToValidate 和 ErrorMessage 屬性。
您可以使用 Microsoft Visual Studio? .NET 中的屬性窗口設置驗證表達式,也可以使用 Page_Load 事件處理程序動態(tài)設置屬性。后者允許您將頁面中所有控件的正則表達式集中分在一組。
Regex 類
如果在常規(guī)的 HTML 控件中不使用 runat="server" 屬性(除了使用 RegularExpressionValidator 控件的情形),或需要驗證來自其他源(像查詢字符串或 cookie)中的輸入,則可在頁類或驗證幫助程序方法中使用 Regex 類(可能在獨立的程序集中)。本節(jié)稍后將給出一些示例。
正則表達式注釋
如果使用下面的語法并使用表達式 # 對每個組件進行注釋,則更容易了解正則表達式。要啟用注釋,還必須指定 RegexOptions.IgnorePatternWhitespace,它表明忽略非轉義空格。
Regex regex = new Regex(@"
^ # 起始標記
(?=.*\d) # 必須至少包含一個數(shù)字
(?=.*[a-z]) # 必須包含一個小寫字母
(?=.*[A-Z]) # 必須包含一個大寫字母
.{8,10} # 字符長度從 8 到 10
$ # 結束標記,
RegexOptions.IgnorePatternWhitespace); 字符串字段
要驗證字符串字段(如名稱、地址和納稅辨識號等),請使用正則表達式執(zhí)行下列操作:
| ? | 約束輸入字符的允許范圍。 |
| ? | 應用格式規(guī)則。例如,基于模式的字段(如納稅辨識號、ZIP 代碼或郵政編碼)必須使用特定模式的輸入字符。 |
| ? | 檢查長度。 |
名稱
下面的示例說明了已在驗證名稱字段中使用的 RegularExpressionValidator 控件。
<form id="WebForm" method="post" runat="server">
<asp:TextBox id="txtName" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator id="nameRegex"runat="server"
ControlToValidate="txtName"
ValidationExpression="^[a-zA-Z'.`-′\s]{1,40}$"
ErrorMessage="Invalid name">
</asp:regularexpressionvalidator>
</form>
上述驗證表達式在輸入名稱字段中限定使用字母字符(大小寫均可)、一個名稱省略符號(如 O'Dell)和點號。此外,字段長度不得超過 40 個字符。
社會保險號
下面的示例顯示了為 RegularExpressionValidator 控件生成的 HTML 代碼。該控件用于驗證美國社會保險號表單域:
<form id="WebForm" method="post" runat="server">
<asp:TextBox id="txtSSN" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator id="ssnRegex" runat="server"
ErrorMessage="Invalid social security number"
ValidationExpression="\d{3}-\d{2}-\d{4}"
ControlToValidate="txtSSN">
</asp:RegularExpressionValidator>
</form>
上述驗證表達式是 Visual Studio .NET 的標準表達式之一。使用該表達式可驗證給定輸入字段的格式、類型和長度。輸入格式必須是:三個數(shù)字 + 一個短劃線;兩個數(shù)字 + 一個短劃線;或四個數(shù)字。
如果使用的不是服務器控件(除了驗證程序控件),或需要驗證來自表單域以外的源的輸入,可在方法代碼中使用 System.Text.RegularExpression.Regex 類。下面的示例說明了如何在頁類中直接使用靜態(tài) Regex.IsMatch 方法而不使用驗證程序控件來驗證相同的字段:
if (!Regex.IsMatch(txtSSN.Text, @"^\d{3}-\d{2}-\d{4}$"))
{
// 社會保險號無效
} 日期字段
具有相同 .NET Framework 類型的輸入字段可由 .NET Framework 類型系統(tǒng)來檢查類型。例如,要驗證日期,您可以在輸入數(shù)據(jù)不兼容的情況下,將輸入值轉換成 System.DateTime 類型的變量,然后處理得到的所有格式異常,如下所述。
try
{
DateTime dt = DateTime.Parse(txtDate.Text).Date;
}
// 如果類型轉換失敗,將觸發(fā) FormatException
catch( FormatException ex )
{
// 將無效日期消息返回給調用者
}
除了檢查格式和類型,您可能還需檢查日期字段的范圍。使用 DateTime 可輕松執(zhí)行此項操作,如下所述。
// 為簡單起見省略了異常處理
DateTime dt = DateTime.Parse(txtDate.Text).Date;
// 日期必須是今天或之前
if ( dt > DateTime.Now.Date )
throw new ArgumentException("Date must be in the past"); 數(shù)字字段
如果需要驗證數(shù)字數(shù)據(jù)(如年齡),請使用 int 類型檢查類型。要將字符串輸入轉換成整數(shù)格式,可以使用 Int32.Parse 或 Convert.ToIn32,然后處理出現(xiàn)無效數(shù)據(jù)類型的所有 FormatException,如下所述。
try
{
int i = Int32.Parse(txtAge.Text);
. . .
}
catch( FormatException)
{
. . .
} 范圍檢查
有時,您需要驗證輸入數(shù)據(jù)是否都在預設的范圍中。下面的代碼使用了 ASP.NET 的 RangeValidator 控件將輸入范圍限制在 0 到 255 之間。此外,本例還使用了 RequiredFieldValidator。如果不使用 RequiredFieldValidator,其他驗證程序控件將接受空輸入。
<form id="WebForm3" method="post" runat="server"> <asp:TextBox id="txtNumber" runat="server"></asp:TextBox> <asp:RequiredFieldValidator id="rangeRegex" runat="server" ErrorMessage="Please enter a number between 0 and 255" ControlToValidate="txtNumber" style="LEFT:10px; POSITION:absolute; TOP:47px" > </asp:RequiredFieldValidator> <asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Please enter a number between 0 and 255" ControlToValidate="TextBox1" Type="Integer" MinimumValue="0" MaximumValue="255" style="LEFT:10px; POSITION:absolute; TOP:47px" > </asp:RangeValidator> <asp:Button id="Button1" style="LEFT:10px; POSITION:absolute; TOP:100px" runat="server" Text="Button"></asp:Button> </form>
下面的示例說明了如何使用 Regex 類驗證范圍:
try
{
// 如果無效,轉換將觸發(fā)異常。
int i = Convert.ToInt32(sInput);
if ((0 <= i && i <= 255) == true)
{
// 數(shù)據(jù)無效,請使用編號
}
}
catch( FormatException )
{
. . .
}
凈化輸入
凈化的作用是確保可能有惡意目的的數(shù)據(jù)的安全。如果許可的輸入范圍不能保證輸入安全,使用此方法非常有用。這包含了去除用戶提供的字符串末尾的空值或轉義值,以便系統(tǒng)將其視為文字。如果需要凈化輸入并轉換或去除特定的輸入字符,請使用 Regex.Replace。
注意:使用此方法可實施深層防御。請在開始時始終將輸入限定在已知“安全”值集的范圍內。
下面的代碼去掉了一組可能不安全的字符,包括 <>\"'%;()&。
private string SanitizeInput(string input)
{
Regex badCharReplace = new Regex(@"^([<>""'%;()&])$");
string goodChars = badCharReplace.Replace(input, "");
return goodChars;
}
有關凈化任意格式輸入字段(如注釋字段)的詳細信息,請參閱本模塊后的跨站點腳本中的“凈化任意格式輸入”。
驗證 HTML 控件
如果不使用服務器控件(即有 runat="server" 屬性的控件),而使用常規(guī) HTML 控件,您不能使用 ASP.NET 驗證程序控件。但可以在 Page_Load 事件處理程序中使用正則表達式來驗證 Web 頁的內容,如下所示。
using System.Text.RegularExpressions;
. . .
private void Page_Load(object sender, System.EventArgs e)
{
// 請注意,IsPostBack 僅適用于
// 服務器形式(有 runat="server")
if ( Request.RequestType == "POST" ) // 非服務器形式
{
// 驗證提供的電子郵件地址
if( !Regex.Match(Request.Form["email"],
@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$",
RegexOptions.None).Success)
{
// 無效電子郵件地址
}
// 驗證提供的名稱
if ( !RegEx.Match(Request.Form["name"],
@"^[A-Za-z'\- ]$",
RegexOptions.None).Success)
{
// 無效名稱
}
}
}
驗證用于訪問數(shù)據(jù)的輸入
如果基于用戶輸入來生成動態(tài) SQL 查詢,SQL 注入攻擊可注入由數(shù)據(jù)庫執(zhí)行的惡意 SQL 命令。在典型的基于 Web 的數(shù)據(jù)訪問中,可使用下列深層防御戰(zhàn)略:
| ? | 使用正則表達式來約束頁類中的輸入。 |
| ? | 凈化或拒絕輸入。為了進行深層防御,您可以借助幫助程序去掉空字符或其他已知的“壞”字符。 |
| ? | 為數(shù)據(jù)訪問使用參數(shù)化存儲過程,確保檢查 SQL 查詢中使用的數(shù)據(jù)的類型和長度。 |
有關為數(shù)據(jù)訪問使用參數(shù)及編寫安全數(shù)據(jù)訪問代碼的詳細信息,請參閱模塊 14 構建安全的數(shù)據(jù)訪問。
驗證用于文件 I/O 的輸入
通常,您應避免使編寫的代碼接受來自調用者的文件輸入或路徑輸入。正確的做法是,在讀取和編寫數(shù)據(jù)時使用固定的文件名和位置。這可確保您的代碼不會被用來強制訪問任意文件。此外,還可確保代碼不容易遭受規(guī)范化 Bug 的攻擊。
如果確實要接受輸入文件名,需面臨兩個主要挑戰(zhàn)。首先,結果文件路徑和名稱是否是有效的文件系統(tǒng)名稱?其次,路徑是否在應用程序上下文中有效?例如,路徑是否位于應用程序虛擬目錄的根目錄下?
要使文件名規(guī)范化,請使用 System.IO.Path.GetFullPath。要檢查文件路徑是否在應用程序上下文中有效,可使用 .NET 代碼訪問安全性向您的代碼授予精確的 FileIOPermission,以便只能訪問特定目錄中的文件。有關詳細信息,請參閱模塊 7 構建安全的程序集中的“文件 I/O”部分和模塊 8 代碼訪問安全的實踐。
使用 MapPath
如果使用 MapPath 將提供的虛擬路徑映射到服務器中的某一物理路徑,請使用接受 bool 參數(shù)的 Request.MapPath 重載,以防止跨應用程序映射,如下所示:
try
{
string mappedPath = Request.MapPath( inputPath.Text,
Request.ApplicationPath, false);
}
catch (HttpException)
{
// 嘗試跨應用程序映射
}
最終的 false 參數(shù)可防止跨應用程序映射。這意味著,用戶不能成功提供包含“..”的路徑來遍歷應用程序虛擬目錄層次結構的外部。任何執(zhí)行該操作的企圖都將造成 HttpException 異常類型。
注意:服務器控件可使用 Control.MapPathSecure 方法來讀取文件。此方法要求代碼訪問安全策略授予調用代碼以完全信任;否則將觸發(fā) HttpException。有關詳細信息,請參閱 .NET Framework SDK 文檔中的 Control.MapPathSecure。
常用正則表達式
Visual Studio .NET 提供了一組非常有用的正則表達式。要訪問這些表達式,請在 Web 窗體中添加 RegularExpresssionValidator 控件,然后單擊控件 Expression 屬性字段中的省略號按鈕。下表顯示了另外幾個在常用 Web 頁字段中非常有用的表達式。
表 10.2:常用的正則表達式字段
| 字段 | 表達式 | 格式示例 | 說明 |
| 名稱 | [a-zA-Z'`-′\s]{1,40} | John DoeO'Dell | 驗證名稱。最多允許使用 40 個大寫字母和小寫字母,以及一些在名稱中常用的特殊字符。此列表可進行調整。 |
| 數(shù)字 | ^\D?(\d{3})\D?\D?(\d{3})\D?(\d{4})$ | (425)-555-0123 | 驗證美國電話號碼。 |
| 電子郵件 | \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* | mailto:test@test.com | 驗證電子郵件地址。 |
| URL | ^(http|https|ftp)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*$ | ?? | 驗證 URL。 |
| 郵政編碼 | ^(\d{5}-\d{4}|\d{5}|\d{9})$|^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$ | ?? | 驗證允許使用 5 個或 9 個數(shù)字的美國郵政編碼。 |
| 密碼 | ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ | ?? | 驗證強密碼。字符數(shù)必須在 8 至 10 的范圍內。必須包含大小寫字母和數(shù)字的組合,不能使用特殊字符。 |
| 非負整數(shù) | \d+ | 0986 | 驗證大于零的整數(shù)。 |
| 貨幣(非負數(shù)) | "\d+(\.\d\d)?" | ?? | 驗證正貨幣金額。要求小數(shù)點后有兩位數(shù)字。 |
| 貨幣(正數(shù)或負數(shù)) | "(-)?\d+(\.\d\d)?" | ?? | 驗證正負貨幣金額。要求小數(shù)點后有兩位數(shù)字。 |
跨站點腳本
XSS 攻擊可通過注入客戶端腳本代碼來探測 Web 頁驗證中的漏洞。代碼隨后被送回信任用戶,并由瀏覽器來執(zhí)行。由于瀏覽器是從信任站點下載腳本代碼的,因此不識別代碼是否合法,Internet Explorer 安全區(qū)域不提供任何防御措施。此外,XSS 攻擊還可通過 HTTP 或 HTTPS (SSL) 連接來起作用。最嚴重的探測情況是,攻擊者編寫腳本來檢索提供信任站點訪問權限的身份驗證 cookie,然后將該 cookie 傳遞給攻擊者已知的 Web 地址。這樣,攻擊者便盜用了合法用戶的身份,從而非法獲取網(wǎng)站的訪問權限。
使用下列對策可防止 XSS 攻擊:
| ? | 驗證輸入 |
| ? | 編碼輸出 |
驗證輸入
請使用本模塊前面提到的各項技術來驗證從應用程序信任范圍以外接收到的任意輸入的類型、長度、格式和范圍。
編碼輸出
如果要編寫 Web 頁的文本輸出,但不確信文本中是否包含 HTML 特殊字符(如 <、> 和 &),請確保使用 HttpUtility.HtmlEncode 方法對其進行預處理。即使文本來自于用戶輸入、數(shù)據(jù)庫或本地文件,也必須這樣做。同樣,請使用 HttpUtility.UrlEncode 對 URL 字符串進行編碼。
HtmlEncode 方法可將 HTML 中有特殊意義的字符替換為代表這些字符的 HTML 變量。例如,< 用 < 替換," 用 " 替換。經(jīng)過編碼的數(shù)據(jù)不會令瀏覽器執(zhí)行代碼。實際上,數(shù)據(jù)是作為無害的 HTML 來顯示的。
Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));
數(shù)據(jù)綁定控件
數(shù)據(jù)綁定 Web 控件不會對輸出進行編碼。唯一編碼輸出的控件是 TextBox 控件,而且 TextMode 屬性要設置為 MultiLine。如果您將任意其他控件綁定在有惡意 XSS 代碼的數(shù)據(jù)中,代碼將在客戶端中執(zhí)行。因此,如果要從數(shù)據(jù)庫中檢索數(shù)據(jù),但又不確信數(shù)據(jù)是否有效(可能由于數(shù)據(jù)庫與其他應用程序共享),您必須在將數(shù)據(jù)傳回客戶端前對其進行編碼。
凈化任意格式的輸入
如果 Web 頁中有任意格式的文本框(如“注釋”字段),而您希望在其中使用較安全的 HTML 元素(如 <b> 和 <i>),則可首先使用 HtmlEncode 進行預處理,然后有選擇性地刪除許可元素中的編碼,從而實現(xiàn)安全處理的目的,如下所示:
StringBuilder sb = new StringBuilder( HttpUtility.HtmlEncode(userInput) ) ;
sb.Replace("<b>", "<b>");
sb.Replace("</b>", "</b>");
sb.Replace("<i>", "<i>");
sb.Replace("</i>", "</I>");
Response.Write(sb.ToString());
深層防御對策
除了前面提到的技術,您還可以使用下列深層防御對策來防止 XSS:
| ? | 設置正確的字符編碼。 |
| ? | 使用 ASP.NET 版本 1.1 的 validateRequest 選項。 |
| ? | 在 Web 服務器中安裝 URLScan。 |
| ? | 使用 HttpOnly cookie 選項。 |
| ? | 使用 <frame> 安全屬性。 |
| ? | 使用 innerText 屬性。 |
設置正確的字符編碼
要成功限制在 Web 頁中有效的數(shù)據(jù),最重要的是限制輸入數(shù)據(jù)的表示方式。這可防止惡意用戶使用規(guī)范化和多字節(jié)轉義序列來哄騙輸入驗證例程。
借助于 Web.config 中的 <globalization> 元素,ASP.NET 允許您指定頁面級或應用程序級的字符集。下面介紹了這兩種方法,二者均使用了 HTML 和 HTTP 早期版本中的默認 ISO-8859-1 字符編碼。
要設置頁面級字符編碼,請使用 <meta> 元素或 ResponseEncoding 頁面級屬性,如下所示:
<meta http-equiv="Content Type" content="text/html; charset=ISO-8859-1" />
或
<% @ Page ResponseEncoding="ISO-8859-1" %>
要在 Web.config 中設置字符編碼,請使用下面的配置:
<configuration> <system.web> <globalization requestEncoding="ISO-8859-1" responseEncoding="ISO-8859-1"/> </system.web> </configuration>
驗證 Unicode 字符
使用下面的代碼可驗證頁面中的 Unicode 字符:
using System.Text.RegularExpressions;
. . .
private void Page_Load(object sender, System.EventArgs e)
{
// 名稱的字母字符數(shù)必須介于 1 至 40 之間
// 還可在名稱中使用(可選)特殊字符 '`′,例如,
// D'Angelo
if (!Regex.IsMatch(Request.Form["name"], @"^[\p{L}\p{Zs}\p{Lu}\p{Ll}]{1,40}$"))
throw new ArgumentException("Invalid name parameter");
// 使用單獨的正則表達式來驗證其他參數(shù)
. . .
}
下面的內容說明了上述代碼中的正則表達式:
| ? | {<name>} 指定一個已命名的 Unicode 字符類。 |
| ? | \p{<name>} 將已命名字符類中的任意字符與 {<name>} 中指定的字符匹配。 |
| ? | {L} 按從左到右的順序匹配。 |
| ? | {Lu} 執(zhí)行大寫字母匹配。 |
| ? | {Ll} 執(zhí)行小寫字母匹配。 |
| ? | {Zs} 匹配分隔符和空格。 |
| ? | {1,40} 表示字符數(shù)大于等于 1,小于等于 40。 |
| ? | {Mn} 匹配標記和無空格字符。 |
| ? | {Zs} 匹配分隔符和空格。 |
| ? | * 指定無匹配項或有多個匹配項。 |
| ? | $ 表示停止在此位置查找。 |
使用 ASP.NET 的 validateRequest 選項
validateRequest 屬性是 .NET Framework 版本 1.1 的特點之一。在默認情況下,該屬性在 Machine.config 的 <pages> 元素中設置,且值為“True”。該屬性要求 ASP.NET 檢查從瀏覽器中接收的所有數(shù)據(jù)是否有潛在的惡意輸入,例如包含 <script> 元素的輸入。ASP.NET 可檢查從 HTML 表單域、cookies 和查詢字符串中接收的輸入。.NET Framework 版本 1.0 不提供任何等價功能,但 IIS URLScan Internet 服務器應用程序編程接口 (ISAPI) 篩選器可執(zhí)行類似工作。您還可以將該設置應用于每個使用 @ Page 標記的頁面,如下所示:
<% @ Page validateRequest="True" %>
在 Web 服務器中安裝 URLScan
URLScan 是一種運行 IISLockdown 工具時安裝的 ISAPI 篩選器。它有助于緩解 XSS 攻擊帶來(通過注入潛在的惡意輸入)的風險。有關 IISLockdown 和 URLScan 的詳細信息,請參閱模塊 16 保護 Web 服務器。
注意:Windows Server 2003 中的 IIS 6.0 有與 URLScan 相同的內置功能。
使用 HttpOnly Cookie 選項
Internet Explorer 6 Service Pack 1 支持新的 HttpOnly cookie 屬性,可防止客戶端腳本訪問 document.cookie 屬性中的 cookie。實際上返回的是空字符串。只要用戶瀏覽當前域中的 Web 站點,系統(tǒng)仍將 cookie 發(fā)送至服務器。
注意:不支持 HttpOnly cookie 屬性的 Web 瀏覽器將忽略 cookie 或忽略屬性,這表示它仍將遭受 XSS 攻擊。
System.Net.Cookie 類當前不支持 HttpOnly 屬性。要將 HttpOnly 屬性添加到 cookie 中,您必須使用 ISAPI 篩選器;如果要使用托管代碼解決方案,請將下面的代碼添至應用程序的 Application_EndRequest 事件處理程序中(在 Global.asax 中):
protected void Application_EndRequest(Object sender, EventArgs e)
{
string authCookie = FormsAuthentication.FormsCookieName;
foreach (string sCookie in Response.Cookies)
{
// 只要在表單身份驗證 cookie 中設置 HttpOnly 屬性
// 跳過該檢查可在集合中的所有 cookie 中設置該屬性
if (sCookie.Equals(authCookie))
{
// 強制將 HttpOnly 添加到 cookie 頭中
Response.Cookies[sCookie].Path += ";HttpOnly";
}
}
}
注意:在 .NET Framework 將來的版本中,Cookie 類可能有 HttpOnly 屬性。
使用 <frame> 安全屬性
Internet Explorer 6 和更高版本都支持 <frame> 和 <iframe> 元素中的新屬性 security。您可以使用 security 屬性將用戶受限站點 Internet Explorer 安全區(qū)域的設置應用于單獨的 frame 或 iframe。在默認情況下,受限站點區(qū)域不支持執(zhí)行腳本。如果要使用 security 屬性,當前必須將其設置為“restricted”,如下所示:
<frame security="restricted" src="http://www.somesite.com/somepage.htm"></frame>
使用 innerText 屬性
如果使用不信任的輸入內容創(chuàng)建頁,請使用 innerText 屬性,而不是 innerHTML。innerText 屬性不僅可呈現(xiàn)安全內容,而且可確保不執(zhí)行腳本。
返回頁首身份驗證
薄弱的身份驗證將增加遭受身份哄騙攻擊的風險。如果用戶的登錄憑據(jù)不慎落入黑手,攻擊者可騙取用戶的身份,然后獲得應用程序的訪問權限。攻擊者因此享有用戶在應用程序中的所有權限。在網(wǎng)絡中傳遞的憑據(jù)必須嚴加保護;如果憑據(jù)是永久性的(例如,在應用程序的用戶存儲中),更要嚴格保護。在初始登錄后使用的那些代表應用程序已驗證身份的身份驗證 cookie 也必須保護,以降低會話劫持風險和 cookie 重播攻擊風險。
表單身份驗證
會話劫持和 cookie 重播攻擊風險對使用表單身份驗證的應用程序的影響尤其嚴重。如果您使用用戶提供的憑據(jù)來查詢數(shù)據(jù)庫,必須提高警惕,確保不會遭受 SQL 注入的攻擊。此外,為了防止身份哄騙,您必須確保用戶存儲安全,并強制使用強密碼。
下面的程序段顯示了 Web.config 中“安全”表單身份驗證配置:
<forms loginUrl="Restricted\login.aspx" Login page in an SSL protected folder protection="All" Privacy and integrity requireSSL="true" Prevents cookie being sent over http timeout="10" Limited session lifetime name="AppNameCookie" Unique per-application name path="/FormsAuth" and path slidingExpiration="true" > Sliding session lifetime </forms>
下列建議可幫助您構建安全的表單身份驗證解決方案:
| ? | 對網(wǎng)站進行分區(qū)。 |
| ? | 確保在受限頁面安全方面使用 SSL。 |
| ? | 使用 URL 授權。 |
| ? | 確保身份驗證 cookie 安全。 |
| ? | 使用絕對 URL 導航。 |
| ? | 使用安全的憑據(jù)管理。 |
對網(wǎng)站進行分區(qū)
在站點設計中,確保將那些要求驗證訪問身份的安全頁面置于不同于匿名訪問頁面所在的子目錄中。圖 10.3 顯示了 Visual Studio .NET 解決方案資源管理器窗口中的典型排列。請注意,窗體登錄頁與其他受限頁面一起放在獨立的子目錄中。
圖 10.3
“要求驗證訪問身份的受限頁面所在的子目錄”
注意:如果在應用程序中使用 Server.Transfer 從匿名頁面中提取信息并傳輸至安全頁面,.NET Framework 版本 1.1 或早期版本將繞過身份驗證檢查,因此您必須驗證使用 Server.Transfer 的代碼,確保不會傳輸?shù)桨踩夸浿小?/p>
確保在受限頁面的安全方面使用 SSL
要確保使用 SSL 來保護從登錄窗體投遞的登錄憑據(jù),以及傳遞給受限頁面后續(xù)請求的身份驗證 cookie,請配置 IIS 中的安全文件夾,使之使用 SSL。這將設置 IIS 元數(shù)據(jù)庫中文件夾的 AccessSSL=true 屬性。只有在請求 URL 中使用 https,對安全文件夾中頁面的請求才能成功。
對于 SSL,您必須在 Web 服務器中安裝服務器證書。有關詳細信息,請參閱 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/secnetlpMSDN.asp 中的“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To: Setup SSL on a Web Server”(英文)。
使用 URL 授權
要許可匿名訪問公共頁面,請使用下面的 <authorization> 元素。
<system.web> <!-- 虛擬目錄根文件夾包含常規(guī)頁面。 未經(jīng)身份驗證的用戶可查看它們,但不需要 使用 SSL 保護。 --> <authorization> <allow users="*" /> </authorization> </system.web>
使用下面的 <authorization> 元素(位于 Web.config 中的 <location> 元素內)可拒絕未經(jīng)身份驗證的用戶的訪問,并強制重定向至 <forms> 元素指定的登錄頁:
<!-- 受限文件夾僅用于身份驗證和 SSL 訪問。 --> <location path="Secure" > <system.web> <authorization> <deny users="?" /> </authorization> </system.web> </location>
確保身份驗證 cookie 的安全
要防止會話劫持和 cookie 重播,請確保 cookie 只能通過使用 HTTPS 協(xié)議的 SSL 連接,從而確保其安全。為了減少其他風險,請在將 cookie 發(fā)至客戶端前對其進行加密,并限制有效期。要確保身份驗證 cookie 安全,請執(zhí)行下列操作:
| ? | 限定身份驗證 cookie 只能通過 HTTPS 連接傳遞。 |
| ? | 加密 cookie。 |
| ? | 限制 cookie 的生命周期。 |
| ? | 考慮使用固定的有效期。 |
| ? | 不保留身份驗證 cookie。 |
| ? | 使身份驗證 cookie 和個性化 cookie 分開。 |
| ? | 使用獨特的 cookie 名稱和路徑。 |
限定身份驗證 cookie 只能通過 HTTPS 連接傳遞
cookie 支持使用“secure”屬性確定瀏覽器是否應將 cookie 送回服務器。如果設置了安全屬性,瀏覽器只能將 cookie 發(fā)送至使用 HTTPS URL 請求的安全頁面。
如果使用 .NET Framework 1.1 版,請使用 <forms> 元素中的 requireSSL="true" 設置安全屬性,如下所述:
<forms loginUrl="Secure\Login.aspx" requireSSL="true" . . . />
如果使用 .NET Framework 1.0 版,請在 Global.asax 的 Application_EndRequest 事件處理程序中手動設置安全屬性,代碼如下:
protected void Application_EndRequest(Object sender, EventArgs e)
{
string authCookie = FormsAuthentication.FormsCookieName;
foreach (string sCookie in Response.Cookies)
{
if (sCookie.Equals(authCookie))
{
// 設置安全 cookie。瀏覽器只將 cookie
// 發(fā)送至使用 https 請求的頁面
Response.Cookies[sCookie].Secure = true;
}
}
}
加密 cookie
即便已使用 SSL,請加密 cookie 內容。這可在攻擊者企圖利用 XSS 竊取 cookie 時防止其查看或修改 cookie。此時,攻擊者仍將使用該 cookie 訪問您的應用程序。降低這種風險的最佳方法是,采取相應對策來防止 XSS 攻擊(如本模塊前面介紹的跨站點腳本),然后按后面給出的建議限制 cookie 的生命周期。
為了提供 cookie 的隱私性和完整性,請在 <forms> 元素中設置 protection 屬性,如下所述:
<forms protection="All" Privacy and integrity
限制 Cookie 的生命周期
限制 cookie 的生命周期可減少攻擊者使用盜用的 cookie 騙取應用程序訪問權限的時間窗口。
<forms timeout="10" Reduced cookie lifetime (10 minutes)
考慮使用固定的有效期
在 <forms> 元素中設置 slidingExpiration="false",從而固定 cookie 的有效期,而不是在發(fā)出每個 Web 請求后對該有效期進行重置。如果未使用 SSL 保護 cookie,這種做法非常重要。
注意:.NET Framework 1.1 版可提供此項功能。
不保留身份驗證 Cookie
不要保留身份驗證 cookie,因為它們保存在用戶配置文件中,如果攻擊者能實際訪問用戶的計算機,則可能竊取到這些信息。如果使用下面的方法創(chuàng)建 FormsAuthenticationTicket,可指定不保留的 cookie:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket( 1, // 版本 Context.User.Identity.Name, // 用戶名 DateTime.Now, // 發(fā)布時間 DateTime.Now.AddMinutes(15), // 每隔 15 分鐘過期 false, // 不保留 cookie roleStr ); // 用戶角色
使身份驗證 cookie 和個性化 cookie 分開
請將包含用戶特定首選項和非敏感數(shù)據(jù)的個性化 cookie 與身份驗證 cookie 分開。如果個性化 cookie 被盜用,可能不會造成安全威脅;但攻擊者可通過盜用的身份驗證 cookie 訪問您的應用程序。
使用獨特的 cookie 名稱和路徑
在 <forms> 元素中使用唯一的 name 和 path 屬性值。如果名稱唯一,可在同一服務器駐留多個應用程序時防止出現(xiàn)潛在的問題。例如,如果不使用獨特的名稱,通過某一應用程序身份驗證的用戶無需重定向至另一應用程序的登錄頁即可請求訪問該應用程序。
有關詳細信息,請參閱 Microsoft 知識庫中的文章 313116 PRB: Forms Authentication Requests Are Not Directed to loginUrl Page(英文)和 310415 PRB:Mobile Forms Authentication and Different Web Applications(英文)。
使用絕對 URL 導航
由于重定向始終使用當前頁(非目標頁)的協(xié)議(HTTPS 或 HTTP),因此在站點公共區(qū)域和受限區(qū)域間(即在 HTTP 和 HTTPS 頁間)導航會發(fā)生問題。
一旦用戶登錄并瀏覽通過 SSL 保護的目錄中的頁面,像“..\publicpage.aspx”這樣的相對鏈接或重定向至 HTTP 頁都會使當前頁面使用 https 協(xié)議,因此帶來不必要的性能負荷。為了避免上述情形,請在將 HTTPS 頁重定向至 HTTP 頁時使用絕對鏈接(如 http://servername/appname/publicpage.aspx)。
同樣,如果從站點公共區(qū)域重定向至安全頁面(如登錄頁),必須使用 HTTPS 絕對路徑(如 https://servername/appname/secure/login.aspx),而不要使用相對路徑(如 restricted/login.aspx)。例如,如果 Web 頁提供了登錄按鈕,請使用下列代碼重定向至安全登錄頁。
private void btnLogon_Click( object sender, System.EventArgs e )
{
// 使用服務器名和 v-dir 名稱構建絕對路徑
string serverName =
HttpUtility.UrlEncode(Request.ServerVariables["SERVER_NAME"]);
string vdirName = Request.ApplicationPath;
Response.Redirect("https://" + serverName + vdirName +
"/Restricted/Login.aspx");
} 使用安全的憑據(jù)管理
在應用程序中,與身份相關的常見威脅之一就是哄騙。如果攻擊者冒充其他用戶身份訪問應用程序,即發(fā)生身份哄騙現(xiàn)象。哄騙的方法之一是攔截會話 cookie。如果您已按照前面提出的方法確保了身份驗證 cookie 的安全,則可大大降低危險。此外,您必須構建安全的憑據(jù)管理和用戶存儲,從而降低強力密碼攻擊、字典攻擊和 SQL 注入攻擊的風險。
下面的建議有助于降低風險:
| ? | 在密碼中使用單向哈希值。 |
| ? | 使用強密碼。 |
| ? | 禁止 SQL 注入。 |
在密碼中使用單向哈希值
如果用戶存儲是 SQL Server,請使用附加的隨機 salt 值保存單向密碼摘要(哈希值)。附加的 salt 值可降低強力密碼破解攻擊(如字典攻擊)帶來的風險。所謂摘要方法,即您絕不能真正保存密碼。實際上,您是先從用戶處檢索密碼,然后再通過重新計算摘要并與存儲值比較,從而對該密碼進行驗證。
使用強密碼
使用正則表達式可確保用戶密碼符合強密碼原則。使用下面的正則表達式可確保密碼的長度在 8 至 10 個字符之間,并包含大小寫字母、數(shù)字和特殊字符。這樣,字典攻擊的風險將進一步降低。
private bool IsStrongPassword( string password )
{
} 禁止 SQL 注入
鑒于用戶提供的登錄憑據(jù)查詢數(shù)據(jù)庫的方式,表單身份驗證特別容易受到 SQL 注入攻擊。要降低風險,請執(zhí)行下列操作:
| ? | 全面驗證提供的憑據(jù)。使用正則表達式確保 SQL 字符不包含在內。 |
| ? | 使用參數(shù)化存儲過程訪問用戶存儲數(shù)據(jù)庫。 |
| ? | 使用受限且特權最低的數(shù)據(jù)庫登錄。 |
有關禁止 SQL 注入的詳細信息,請參閱模塊 14 構建安全的數(shù)據(jù)訪問。
返回頁首授權
您可通過授權來控制對目錄、獨立 Web 頁、頁類和方法等的訪問。如果需要,還可在方法代碼中包含授權邏輯。在 Web 頁和控件中構建授權時,請考慮下列建議:
| ? | 使用 URL 授權來控制對 Web 頁和目錄的訪問。 |
| ? | 使用包含 Windows 身份驗證的文件授權。 |
| ? | 在類和方法中使用主體請求。 |
| ? | 使用顯式的角色檢查來精確授權。 |
使用 URL 授權來控制對 Web 頁和目錄的訪問
對于頁面級和目錄級的訪問控制,請使用 URL 授權(通過 <authorization> 元素配置)。要限制對特定文件或目錄的訪問,請將 <authorization> 元素置于 <location> 元素中。
有關詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全中的“授權”部分。
使用包含 Windows 身份驗證的文件授權
如果 ASP.NE 要求 Windows 身份驗證,FileAuthorizationModule 將檢查 ASP.NET 文件類型的所有請求。這些文件類型有:ASP.NET 頁文件 (.aspx)、用戶控件 (.ascx) 以及通過 IIS 映射到 ASP.NET ISAPI 篩選器的任意其他文件類型。
要配置 FileAuthorizationModule,請在 ASP.NET 文件中設置相應的 Windows 訪問控制列表 (ACL)。
在類和方法中使用主體請求
主體權限請求 (Principal permission demand) 允許您基于調用者的身份和角色成員資格制定授權決策。調用者的身份和角色成員資格由主體對象維護。主體對象與當前 Web 請求(通過 HttpContext.User 訪問)相關聯(lián)。使用聲明性安全屬性可控制對類和方法的訪問,如下所述:
// 聲明語法
[PrincipalPermission(SecurityAction.Demand,
Role=@"DomainName\WindowsGroup")]
public void SomeRestrictedMethod()
{
} 使用顯式角色檢查制定精確授權
聲明性安全檢查可防止用戶訪問類或調用特定的方法。如果要在方法中使用附加邏輯來制定授權決策,請使用命令式主體權限請求,或通過 IPrincipal.IsInRole 使用顯式角色檢查。這些方法允許您使用附加的運行時變量來優(yōu)化授權決策。下面的示例顯示了使用命令式主體權限請求的情況:
// 命令式語法
public void SomeRestrictedMethod()
{
// 僅允許屬于指定 Windows 組成員的調用者
// 訪問
PrincipalPermission permCheck = new PrincipalPermission(
null, @"DomainName\WindowsGroup");
permCheck.Demand();
// 一些受限操作(省略)
}
下面的示例顯示了 IPrincipal.IsInRole 的用法:
public void TransferMoney( string fromAccount,
string toAccount, double amount)
{
// 從當前 HTTP 上下文提取經(jīng)身份驗證的用戶。
// 用戶變量等于 HttpContext.Current.User,條件是您
// 使用 .aspx 頁(或 .asmx)
WindowsPrincipal authenticatedUser = User as WindowsPrincipal;
if (null != authenticatedUser)
{
// 注意:要檢索經(jīng)身份驗證的用戶的用戶名,請使用
// 下列代碼行
// 字符串用戶名 = authenticatedUser.Identity.Name;
// 如果值超過閾值,必須通過管理員的審批
if (amount > thresholdValue) {
// 執(zhí)行角色檢查
if (authenticatedUser.IsInRole(@"DomainName\Manager") )
{
// 如果確定,可繼續(xù)傳送
}
else
{
throw new Exception("Unauthorized funds transfer");
}
}
else
{
. . .
}
}
}
此外,您還可以使用允許調用者角色不同的方法。但后面,您可能需要調用不包含聲明性安全內容的其他方法。
返回頁首模擬
在默認情況下,ASP.NET 應用程序一般不因設計、實施和伸縮性等原因來模擬原來的調用者。例如,模擬雖防止了有效的中間層連接池,但它會對應用程序的伸縮性產(chǎn)生嚴重的影響。
但在某些情況下,您可能確實需要模擬(例如,如果要使用備用身份(非進程身份)來訪問資源)。在宿主環(huán)境中,多個匿名身份常作為應用程序隔離的形式使用。例如,如果應用程序使用表單或 Passport 身份驗證,您可使用應用程序的虛擬目錄來模擬與 IIS 關聯(lián)的匿名 Internet 用戶帳戶。
您可以模擬原有的調用者,但可能是匿名 Internet 用戶帳戶或固定身份。要模擬原有調用者(IIS 身份驗證身份),請使用下列配置:
<identity impersonate="true" />
要模擬固定身份,請使用 <identity> 元素中附加的 userName 和 password 屬性,但必須確保使用 Aspnet_setreg.exe 在注冊表中存儲加密的憑據(jù)。有關加密配置文件中的憑據(jù)和有關 Aspnet_setreg.exe 的詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全。
使用編程模擬
如果不想模擬整個請求的帳戶,可使用編程模擬來模擬部分請求。例如,您希望使用 ASP.NET 進程帳戶來訪問應用程序的主要資源和下游數(shù)據(jù)庫,但需要使用備用身份訪問備用的資源(如另一遠程數(shù)據(jù)庫或遠程文件共享)。
為此,請使用 IIS 配置匿名用戶帳戶,使其成為受信任的備用身份。然后,僅在執(zhí)行遠程資源訪問代碼時再使用匿名帳戶創(chuàng)建模擬令牌,代碼如下:
HttpContext context = HttpContext.Current;
// 從上下文中獲取服務提供程序
IServiceProvider iServiceProvider = context as IServiceProvider;
//獲取代表 HttpContext 的類型
Type httpWorkerRequestType = typeof(HttpWorkerRequest);
// 從服務提供程序中獲得 HttpWorkerRequest 服務
// 注意:如果嘗試從 HttpContext 中獲取 HttpWorkerRequest 類型,
// 必須有未托管代碼的權限。
HttpWorkerRequest httpWorkerRequest =
iServiceProvider.GetService(httpWorkerRequestType) as HttpWorkerRequest;
// 獲得 IIS 傳遞的令牌
IntPtr ptrUserToken = httpWorkerRequest.GetUserToken();
// 根據(jù)令牌創(chuàng)建 WindowsIdentity
WindowsIdentity winIdentity = new WindowsIdentity(ptrUserToken);
// 模擬用戶
Response.Write("Before impersonation: " +
WindowsIdentity.GetCurrent().Name + "<br>");
WindowsImpersonationContext impContext = winIdentity.Impersonate();
Response.Write("Impersonating:" + WindowsIdentity.GetCurrent().Name + "<br>);
// 在此放置資源訪問代碼
// 停止模擬
impContext.Undo();
Response.Write( "After Impersonating: " +
WindowsIdentity.GetCurrent().Name + "<br>");
注意:對于這種方法,如果應用程序虛擬目錄在 IIS 中配置為支持匿名訪問,則該方法使用表單或 Passport 身份驗證。
如果使用這里的代碼,請使用下面的 <identity> 配置:
<identity impersonate="false" />
注意:代碼要求具有未托管代碼權限 SecurityPermission(SecurityPermissionFlag.UnmanagedCode),該權限僅授予完全信任 Web 應用程序。
返回頁首敏感數(shù)據(jù)
敏感數(shù)據(jù)包括了應用程序配置詳細信息(例如,連接字符串和服務帳戶憑據(jù))和應用程序特定數(shù)據(jù)(例如,客戶信用卡號)。下面的建議有助于降低處理敏感數(shù)據(jù)時遇到的風險:
| ? | 不在頁與頁之間傳遞敏感數(shù)據(jù)。 |
| ? | 避免在配置文件中使用純文本密碼。 |
| ? | 使用 DPAPI 避免密鑰管理。 |
| ? | 關閉敏感數(shù)據(jù)的輸出緩存功能。 |
不在頁與頁之間傳遞敏感數(shù)據(jù)
避免使用任何客戶端狀態(tài)管理選項(例如,視圖狀態(tài)、cookie、查詢字符串或隱藏表單域變量)來保存敏感數(shù)據(jù)。這些數(shù)據(jù)可被篡改并明文查看。請使用服務器端的狀態(tài)管理選項,如用于安全數(shù)據(jù)交換的 SQL Server 數(shù)據(jù)庫。
避免在配置文件中使用純文本密碼
Machine.config 和 Web.config 中的 <processModel>、<sessionState> 和 <identity> 元素都有 userName 和 password 屬性。不要使用純文本保存這些屬性。請使用 Aspnet_setreg.exe 工具在注冊表中保存加密憑據(jù)。
有關加密配置文件中的憑據(jù)和有關 Aspnet_setreg.exe 的詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全。
使用 DPAPI 避免密鑰管理
DPAPI 非常適于加密機密信息,如連接字符串和服務帳戶憑據(jù)。如果頁面要使用這種類型的配置數(shù)據(jù),請使用 DPAPI 避免密鑰管理問題。
有關詳細信息,請參閱模塊 7 構建安全的程序集中的“加密”部分。
關閉敏感數(shù)據(jù)的輸出緩沖功能
如果頁面包含敏感數(shù)據(jù)(如密碼、信用卡號或帳戶狀況),不應對該頁進行緩存。要關閉特定頁面的緩存功能,請使用下列頁級屬性:
<%@ Page OutputCache Duration="0" Location="None" VaryByParam="None" %>返回頁首
會話管理
在提供安全會話管理時,您應考慮下面兩大主要因素。首先,確保會話令牌無法用來獲取敏感頁面(其中執(zhí)行安全的操作)的訪問權限,或獲取敏感數(shù)據(jù)項的訪問權限。其次,如果會話數(shù)據(jù)中有敏感內容,必須確保會話數(shù)據(jù)(包括會話存儲)的安全。
下面兩種令牌類型都與會話管理關聯(lián):
| ? | 會話令牌:如果啟用會話狀態(tài),ASP.NET 將自動生成該令牌。例如,將 <sessionState> 元素的 mode 屬性設置為 InProc、SQLServer 或 StateServer。 注意:您可以使用 @Page 標記中的 EnableSessionState 屬性覆蓋 <sessionState> 配置,或基于頁面啟用(或禁用)會話狀態(tài)。 |
| ? | 身份驗證令牌:該令牌由身份驗證機制(如表單身份驗證)生成,用于跟蹤身份經(jīng)過驗證的用戶的會話。如果使用有效的身份驗證令牌,用戶可訪問網(wǎng)站中的受限區(qū)域。 |
下列建議有助于您構建安全的會話管理:
| ? | 要求對敏感頁面進行身份驗證。 |
| ? | 不依賴于客戶端的狀態(tài)管理選項。 |
| ? | 不混用會話令牌和身份驗證令牌。 |
| ? | 有效使用 SSL。 |
| ? | 確保會話數(shù)據(jù)安全。 |
要求對敏感頁面進行身份驗證
確保先驗證用戶的身份,然后再許可用戶訪問站點中的敏感區(qū)域和受限區(qū)域。如果使用安全身份驗證并通過 SSL 保護身份驗證令牌,用戶會話就是安全的,因為攻擊者無法攔截和重播會話令牌。攻擊者必須使身份驗證令牌通過授權網(wǎng)關。
有關保護表單身份驗證的身份驗證令牌的詳細信息,請參閱本模塊前面介紹的表單身份驗證。
不依賴于客戶端的狀態(tài)管理選項
避免使用任何客戶端狀態(tài)管理選項(例如,視圖狀態(tài)、cookie、查詢字符串或隱藏表單域)來保存敏感數(shù)據(jù)。這些信息可被篡改并明文查看。請使用服務器端的狀態(tài)管理選項(如數(shù)據(jù)庫)來保存敏感數(shù)據(jù)。
不混用會話令牌和身份驗證令牌
根據(jù)安全會話管理的要求,不能混用兩種類型的令牌。首先,確保身份驗證令牌安全,確保攻擊者無法捕獲該身份驗證令牌,然后使用它訪問應用程序中的受限區(qū)域。其次,在構建應用程序時,確保單獨的會話令牌無法用于訪問敏感頁面或敏感數(shù)據(jù)。會話令牌只能用于個性化用途中,或維護跨多個 HTTP 請求的用戶狀態(tài)。如果不進行身份驗證,請不要維護用戶狀態(tài)中的敏感項目。
有效使用 SSL
如果站點中既有安全區(qū)域,也有公共訪問區(qū)域,必須使用 SSL 保護要求身份驗證的安全區(qū)域。如果用戶在安全區(qū)域和公共區(qū)域間來回移動,ASP.NET – 生成的會話 cookie(如果啟用了 cookie-less 會話狀態(tài),則是 URL)將隨用戶一起以純文本形式移動。但是,只要設置了 Secure cookie 屬性,身份驗證 cookie 便永遠不在未經(jīng)加密的 HTTP 連接中傳遞。
注意:可以通過設置 <forms> 元素中的 requireSSL="true" 來設置表單身份驗證 cookie 的 Secure 屬性。
攻擊者可獲取傳遞于未經(jīng)加密的 HTTP 會話中的會話 cookie,但如果已正確設計站點,并將受限頁面和資源置于獨立的安全目錄中,攻擊者只能使用該 cookie 訪問不安全的公共訪問頁。此時,不存在任何安全方面的威脅,因為這些頁面并不執(zhí)行敏感操作。一旦攻擊者在安全頁面中重播會話令牌,則由于沒有身份驗證令牌,攻擊者只能被重定向至應用程序的登錄頁。
有關使用 Secure cookie 屬性和構建安全表單身份驗證解決方案的詳細信息,請參閱本模塊前面的表單身份驗證。
確保會話數(shù)據(jù)安全
如果服務器中的會話數(shù)據(jù)包含敏感內容,必須確保數(shù)據(jù)和存儲的安全。ASP.NET 支持多種會話狀態(tài)模式。有關確保 ASP.NET 會話狀態(tài)的相關信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全中的“會話狀態(tài)”部分。
返回頁首參數(shù)處理
對于常企圖訪問受限頁面或欺騙應用程序執(zhí)行未授權操作的攻擊者而言,常要處理各種參數(shù),如來自表單域、查詢字符串、視圖狀態(tài)和 cookie 中的參數(shù)。
例如,如果攻擊者獲悉,您的 cookie 使用的身份驗證令牌方案比較薄弱(如號碼可猜到),他(或她)就會使用另一號碼構建 cookie,然后以不同的用戶身份(可能是特權用戶)發(fā)出請求。
下列建議有助于避免參數(shù)處理安全漏洞:
| ? | 使用 MAC 保護視圖狀態(tài)。 |
| ? | 使用 Page.ViewStateUserKey 對付一鍵式 (one-click) 攻擊。 |
| ? | 維護服務器中的敏感數(shù)據(jù)。 |
| ? | 驗證輸入?yún)?shù)。 |
使用 MAC 保護視圖狀態(tài)
如果 Web 頁或控件使用視圖狀態(tài)來維護不同 HTTP 請求的狀態(tài),請確保加密視圖狀態(tài)并使用 MAC 進行完整性檢查。在默認情況下,Machine.config 的 <pages> 元素的 enableViewStateMac 屬性可確保視圖狀態(tài)通過 MAC 保護。
<pages buffer="true" enableSessionState="true" enableViewState="true" enableViewStateMac="true" autoEventWireup="true" validateRequest="true"/>
注意:由于@Page 指令也支持上面提到的屬性,因此您可基于每一頁面自定義設置。
盡管您可以忽略視圖狀態(tài)的啟用是否基于每一控件、每一頁或每一應用程序,但必須確保在使用視圖狀態(tài)時將 enableViewStateMac 設置為 True。
Server.Transfer
如果應用程序按如下方式使用 Server.Transfer,并將第二個可選布爾值參數(shù)設置為 True 來保留 QueryString 和 Form 組合,則命令將在 enableViewStateMac 設置為 True 時失敗。
Server.Transfer("page2.aspx", true);
如果省略第二個參數(shù)或將其設置為 false,則不會出現(xiàn)錯誤。如果要保留 QueryString 和 Form 的組合,而不是將 enableViewStateMac 設置為 false,請參考 Microsoft 知識庫文章 16920 PRB:"View State Is Invalid" Error Message When You Use Server.Transfer(英文)中的解決方案。
有關配置 <machineKey> 元素來加密視圖狀態(tài)和執(zhí)行完整性檢查的詳細信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全。
使用 Page.ViewStateUserKey 對付一鍵式攻擊
如果要驗證調用者的身份并使用視圖狀態(tài),請設置 Page_Init 事件處理程序中的 Page.ViewStateUserKey 屬性,防止出現(xiàn)一鍵式攻擊。如果攻擊者使用視圖狀態(tài)創(chuàng)建預先填充的 Web 頁(.htm 或 .aspx),則發(fā)生一鍵式攻擊。視圖狀態(tài)可根據(jù)攻擊者先前創(chuàng)建的頁面生成。例如,包含 100 種商品的購物車頁面。攻擊者可引誘信任用戶瀏覽該頁,然后將該頁發(fā)送至視圖狀態(tài)有效的服務器。服務器不知道該視圖狀態(tài)是由攻擊者生成的。由于視圖狀態(tài)的有效性,再加上頁面在用戶安全上下文中執(zhí)行,因此視圖狀態(tài)驗證和 MAC 無法對付這種攻擊。
請為 Page.ViewStateUserKey 屬性設置唯一適合的值,然后作為對付一鍵式攻擊的對策。對于每個用戶而言,這個值必須唯一。通常,它是用戶名或標識符。當攻擊者創(chuàng)建視圖狀態(tài)時,常將 ViewStateUserKey 屬性初始化為自己的用戶名。當用戶向服務器提交頁面時,便使用攻擊者的用戶名對該頁進行初始化。因此,視圖狀態(tài) MAC 檢查將失敗,同時出現(xiàn)異常狀況。
注意:通常,這種攻擊對匿名瀏覽的頁面而言(無用戶名)無關緊要,因為匿名瀏覽頁面不執(zhí)行敏感事務處理。
維護服務器中的敏感數(shù)據(jù)
不要信任輸入的參數(shù),特別是要在服務器中制定安全決策的輸入?yún)?shù)。此外,不在任何格式的敏感數(shù)據(jù)中使用明文參數(shù)。而應將服務器中的敏感數(shù)據(jù)保存在會話存儲中,然后使用會話令牌引用存儲中的項目。確保用戶經(jīng)過安全的身份驗證,且身份驗證令牌受到適當?shù)陌踩Wo。有關詳細信息,請參閱本模塊前面的會話管理。
驗證輸入?yún)?shù)
驗證來自表單域、查詢字符串、cookie 和 HTTP 頭中的所有輸入?yún)?shù)。System.Text.RegularExpressions.Regex 類可幫助您驗證輸入?yún)?shù)。例如,下面的代碼顯示了如何使用該類來驗證通過查詢字符串參數(shù)傳遞的名稱。同樣,使用這種方法可驗證其他格式的輸入?yún)?shù),如來自 cookie 或表單域的參數(shù)。例如,要驗證 cookie 參數(shù),使用 Request.Cookies,而不是 Request.QueryString。
using System.Text.RegularExpressions;
. . .
private void Page_Load(object sender, System.EventArgs e)
{
// 名稱的字母字符數(shù)必須介于 1 至 40 之間
還可在名稱中使用(可選)特殊字符 '`′,例如,
// D'Angelo
if (!Regex.IsMatch(Request.QueryString["name"],
@"^[\p{L}\p{Zs}\p{Lu}\p{Ll}]{1,40}$"))
throw new Exception("Invalid name parameter");
// 使用獨立的正則表達式驗證其他所有內容
// 查詢字符串參數(shù)
. . .
}
有關使用正則表達式和驗證輸入數(shù)據(jù)的詳細信息,請參閱本模塊前面的輸入驗證。
返回頁首異常管理
Web 頁中正確的異常處理可防止向用戶泄漏敏感的異常細節(jié)信息。下面的建議適用于 ASP.NET Web 頁和控件。
| ? | 將一般錯誤頁返回給客戶端。 |
| ? | 實施頁面級或應用程序級錯誤處理程序。 |
有關異常管理的詳細信息,請參閱模塊 7 構建安全的程序集。
將一般錯誤頁返回給客戶端
如果有未處理的異常(即傳播至應用程序邊界的異常),一般錯誤頁將返回給用戶。為此,請按如下方式配置 <customErrors> 元素:
<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />
錯誤頁應包含相應的一般錯誤消息,可能還有其他詳細支持信息。生成錯誤的頁面的名稱通過 aspxerrorpath 查詢參數(shù)傳遞到錯誤頁。
此外,您還可針對不同類型的錯誤使用多個錯誤頁。例如:
<customErrors mode="On" defaultRedirect="YourErrorPage.htm"> <error statusCode="404" redirect="YourNotFoundPage.htm"/> <error statusCode="500" redirect="YourInternalErrorPage.htm"/> </customErrors>
對于個別頁面,可使用下面的頁面級屬性提供錯誤頁:
<% @ Page ErrorPage="YourErrorPage" %>
實施頁面級或應用程序級處理程序
如果需要在頁面級捕獲并處理未處理的異常,請為 Page_Error 事件創(chuàng)建如下所述的處理程序。
public void Page_Error(object sender,EventArgs e)
{
// 獲得源異常細節(jié)信息
Exception ex = Server.GetLastError();
// 將詳細信息寫入事件日志以便診斷
. . .
// 防止異常傳播并生成
// 應用程序級事件 (Application.Error)
Server.ClearError();
}
如果允許從頁處理程序傳播異常,或不存在頁處理程序,則出現(xiàn)應用程序錯誤事件。要捕獲應用程序級事件,請實施 Global.asax 中的 Application_Error,如下所述:
protected void Application_Error(Object sender, EventArgs e)
{
// 寫入事件日志。
} 返回頁首 審核和日志記錄
對于 Web 應用程序,默認的 ASP.NET 進程標識可將新的記錄寫入事件日志,但它的權限不足,無法創(chuàng)建新的事件源。要解決該問題,有兩個方案可供選擇。其一,您可以創(chuàng)建一種安裝程序類,專門供管理員權限在安裝時調用;其二,您可以配置 EventLog 注冊表項的權限,允許 ASP.NET 進程標識(或模擬標識)在運行時創(chuàng)建事件源。建議您使用前一種方法。
| ? | 在安裝時創(chuàng)建應用程序事件源
|
如果有現(xiàn)成的應用程序,且不希望創(chuàng)建安裝程序類,您必須授予 ASP.NET 進程標識正確的訪問權限,使其可訪問事件日志注冊表項。有關注冊表項的詳細信息和所需的正確訪問權限,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全中的“事件日志”部分。
EventLogPermission
必須使用代碼訪問安全策略為寫入事件日志的代碼提供 EventLogPermission。如果配置 Web 應用程序在部分信任級別運行,便會出現(xiàn)問題。有關如何從部分信任 Web 應用程序向事件日志寫入信息,請參閱模塊 9 ASP.NET 代碼訪問安全性。
返回頁首小結
本模塊開始介紹了構建 Web 頁和控件必須解決的主要威脅。很多應用程序級攻擊都依賴于輸入驗證中的安全漏洞。多留意這方面的問題可確保驗證策略更加完善,并正確驗證在部分信任源中處理的所有數(shù)據(jù)。另一常見安全漏洞是,無法保護身份驗證 cookie。本模塊的表單身份驗證部分介紹了幾種行之有效的對策,可防止未經(jīng)授權的訪問攻擊、會話劫持攻擊和 cookie 重播攻擊。
返回頁首其他資源
有關詳細信息,請參考下列資源:
| ? | 有關建立安全 Machine.config 和 Web.config 配置的信息,請參閱模塊 19 確保 ASP.NET 應用程序和 Web Services 的安全。 |
| ? | 有關可打印檢查表的信息,請參閱本指南檢查表部分的“檢查表:保護 ASP.NET 的安全。 |
| ? | 有關確保開發(fā)人員工作站安全的相關信息,請參閱本指南的如何:保護開發(fā)人員工作站。 |
| ? | 有關 ASP.NET 中身份驗證和授權的詳細信息,請參閱“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications:Authentication, Authorization, and Secure Communication”中的模塊 8“ASP.NET Security”,網(wǎng)址是:http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetch08.asp(英文)。 |
| ? | 有關使用表單身份驗證的演練,請參閱“How To:Use Forms Authentication with SQL Server 2000”和“How To:Use Forms Authentication with Active Directory”,位于“Microsoft patterns & practices Volume I, Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication”的“How To”部分,網(wǎng)址是 http://msdn.microsoft.com/library/en-us/dnnetsec/html/SecNetHT00.asp(英文)。 |
| ? | 有關使用正則表達式的詳細信息,請參閱 Microsoft 知識庫中的文章 308252 How To:Match a Pattern by Using Regular Expressions and Visual C# .NET(英文)。 |
| ? | 有關 ASP.NET 中的用戶輸入驗證詳細信息,請參閱 MSDN 文章“User Input Validation in ASP.NET”,網(wǎng)址是:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/pdc_userinput.asp(英文)。 |
| ? | 有關 Secure cookie 屬性的詳細信息,請參閱 W3C 網(wǎng)站中的 RFC2109,網(wǎng)址是:http://www.w3.org/Protocols/rfc2109/rfc2109(英文)。 |
| ? | 有關 Open Hack 競爭方面的安全事項詳細信息,請參閱 MSDN 文章構建和配置更安全的網(wǎng)站。 |
轉載于:https://www.cnblogs.com/cxd4321/archive/2008/12/12/1353707.html
總結
以上是生活随笔為你收集整理的构建安全的 ASP.NET 网页和控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个性签名两个字的女生
- 下一篇: [转载]前端工程师应该关注什么