ASP.NET網(wǎng)站防止SQL注入攻擊 目的: •對輸入的字串長度,范圍,格式和類型進行約束. 你應該在程序中驗證所有的不信任輸入.你應該假定所有的用戶輸入都是非法的.用戶可以在應用程序中提供表單字段,查詢字串,客戶端cookies和瀏覽器環(huán)境值比如用戶代理字串和IP地址等. 弱輸入校驗通常為注入攻擊提供了機會.下面是常見的利用弱輸入校驗或無輸入校驗進行攻擊的手段. •SQL 注入(SQL injection). 如果你使用用戶的輸入值來動態(tài)構(gòu)造SQL語句,那么數(shù)據(jù)庫可能執(zhí)行攻擊性的有害SQL語句. •跨站腳本(Cross-site scripting). 跨站腳本攻擊利用網(wǎng)頁驗證漏洞注入客戶端腳本.接下來這些代碼被發(fā)送到受信任的客戶端電腦上并被瀏覽器解釋執(zhí)行.因為這些代碼來自受信任的站點,所以瀏覽器無法得知這些代碼是有害的. •未授權(quán)的文件訪問(Unauthorized file access).如果你的代碼從調(diào)用者那里接受輸入,惡意用戶可以看到你對文件的操作過程從而訪問那些受保護的文件或者使用你的代碼注入非法數(shù)據(jù). 注意 : 注入攻擊可通過使用HTTP或HTTPS Secure Socket Layer(SSL) 連接. 傳輸加密技術(shù)不能用來防御攻擊. 通常的輸入驗證方法總結(jié)如下.你應在所有的需要通過網(wǎng)絡輸入的地方進行驗證,比如文本框和其它表單輸入字段, 查詢字串參數(shù),cookies,服務器端變量和網(wǎng)絡方法參數(shù).注意,過濾策略應該是只允許正確的輸入然后拒絕非法輸入.這是因為定義正確的輸入策略比過濾所有的非法輸入要容易,那通常很難包括所有的非法輸入. 通入如下幾個方面驗證輸入內(nèi)容: •約束.驗證是否輸入的是正確的類型,字符長度,格式和范圍.可以應用ASP.NET驗證控件來約束服務器控件輸入.約束其它來源的輸入可以使用正則表達式和自定義的驗證規(guī)則. •拒絕.檢測已知的有害數(shù)據(jù)輸入并拒絕. •過濾.有時候你會希望過濾掉用戶輸入中那些有安全隱患的那些部分.例如,你的程序允許自由格式的輸入,比如備注字段,你會允許特定的安全HTML標記象<b>,<i>及其它的HTML標記. 步驟提要 通過以下步驟保護你的ASP.NET程序不受注入式攻擊危害 : •第一步.使用ASP.NET請求驗證. 下面的章節(jié)將對這些步驟進行詳細討論. 第一步.使用ASP.NET請求驗證. 默認地,ASP.NET 1.1和2.0請求驗證會對送至服務器的數(shù)據(jù)檢測是否含有HTML標記元素和保留字符.這可以防止用戶向程序中輸入腳本.請求驗證會對照一個有潛在威脅的字符串列表進行匹配,如果發(fā)現(xiàn)異常它會拋出一個HttpRequestValidationException類型的異常. 你可以在你的web.config文件中的<pages>元素中加入validateRequest="false" 或在單獨的頁面的@Pages元素里面設置ValidateRequest = "false"來禁用此項功能. 如果你想禁用請求驗證功能,你可以僅在需要的頁面禁用它.比如你在程序頁面上包含一個可接受HTML格式輸入的字段. 確定在Machine.config文件中請求驗證功能被打開. <pages validateRequest = "true" ... /> 確認你沒有修改你的服務器的Machine.config和應用程序的Web.config文件里的默認設置. 測試ASP.NET請求驗證 你可以測試請求驗證的作用.創(chuàng)建一個ASP.NET頁面通過設置ValidateRequest = "fasle"禁用請求驗證,代碼如下 : <%@ Language="C#" ValidateRequest="false" %> { Response.Write(txtString.Text); 當你運行頁面的時候,"Hello"被顯示在一個消息框中,因為在txtString中的腳本被執(zhí)行并被客戶端的瀏覽器處理. 如果你設置ValidateRequest = "true" 或者移除ValidateRequest頁面屬性,ASP.NET請求驗證會拒絕腳本輸入并拋出一個象下面這樣的錯誤信息. 要約束輸入通過如下方法 : •使用服務器端的輸入驗證.不要依賴于客戶端的驗證,因為它很容易就被繞過.使用客戶端驗證是為了減少頁面返住次數(shù)提升性能,改進用戶體驗. 要驗證表單里面的HTML控件輸入字段,在服務器端代碼中進行驗證,使用Regex正則表達式類型可以幫助約束字符輸入.下面的章節(jié)介紹如何約束普通輸入類型的變量. 驗證字符串字段 •要驗證字符串字段,如姓名,地址,傳真,生份證號碼,使用正則表達式. 使用正則表達式驗證控件(RegularExpresionValidator) 要使用則表達式驗證控件需要設置待驗證的控件名(ControlToValidate),驗證表達式(Validation)和出錯提示(ErrorMessage).相關(guān)的屬性設置請看下面的代碼示例. <form id="WebForm" method="post" runat="server"> 在上面的代碼中,正則表達式被用于限定輸入的名字為字母(允許大寫字母和小寫字母),空格,單名省略號象O'Dell和句點.此外,輸入的字符長度被限定在40個字符. 注意 正則表達式驗證控件(RegularValidator)會自動加入脫字符(^)和美元符號($)作為開始和結(jié)束的分隔符.如果你沒有在自定義的表達式中加入他們那么最好加入.加入分隔符只是為了讓你的表達式得到想要的那部分數(shù)據(jù)內(nèi)容. 使用正則表達式類(Regex Class) 如果你沒有使用服務器端的控件(意味著你不能使用驗證控件),或者你需要其它的輸入字段源而非表單字段(比如查詢字串參數(shù)和cookies),那么你可以使用正則表達式類(Regex class). 使用正則表達式類 •加入使用using前綴的語句導入System.Text.Regulars命名空間. Regex reg = new Regex(@"^[a-zA-Z'.\s]{1,40}$"); if (!Regex.IsMatch(txtName.Text,@"^[a-zA-Z'.\s]{1,40}$"))
} 如果你不能把經(jīng)常使用的正則表達式緩存起來,你應該使用IsMatch靜態(tài)方法來改進性能防止不必要的對象創(chuàng)建過程. 驗證數(shù)字字段 在大多數(shù)情況下,應該驗證數(shù)字的輸入和范圍.使用服務器控件驗證數(shù)字字段的輸入和范圍,使用RangeValidator控件.RangeValidator支持貨幣,日期,整型,雙精度和字符串類型的數(shù)據(jù). 使用RangeValidator控件需要設置需要驗證的控件名(ControlToValidate),類型(Type),最小值(MinimumValue),最大值(MaximumValue),和出錯提示信息(ErrorMessage)屬性.下面是代碼示例 : <asp:RangeValidator 如果你沒使用服務器控件,你可以將輸入值轉(zhuǎn)化成整型再進行驗證來完成對數(shù)字的范圍驗證.例如,要驗證一個整數(shù)是否合法,使用ASP.NET2.0提供的新方法Int32.TryParse將輸入值轉(zhuǎn)化為System.Int32的變量類型.這個方法會在轉(zhuǎn)換失敗時返回false. Int32 i;
} 如果你使用早先的ASP.NET版本,可以在try/catch語句塊中 使用Int32.Parse或者Convert.ToInt32方法并可以在轉(zhuǎn)換失敗時處理拋出的FormatException錯誤. 下面的示例代碼演示了如何驗證來自HTML文本框的整數(shù)類型的類型和范圍. <%@ Page Language="C#" %> { { if ((0 <= i && i <= 255) == true) { <html> 你需要驗證日期字段是否是正確的類型.在大多數(shù)情況下,你也需要驗證它們的范圍,如驗證它們是否是將來或是過去的時間.如果你使用服務器控件來捕獲一個日期輸入值,同時你希望這個值在一個特定的范圍內(nèi),你可以使用范圍驗證控件(RangeValidator)并設置它允許的類型為Date類型.這個控件允許你指定一個特殊的時間段通過設置起始的時刻.如果你需要以今天的時間作為參照來驗證,比如驗證一個時間是在將來還是過去,你可以使用CustomValidator驗證控件。 使用CustomValidator控件來驗證一個日期需要設置ControlToValidate和ErrorMessage屬性,在OnServerValidate事件中指定一個自定義的驗證邏輯方法.下面是示例代碼. <%@ Page Language="C#" %> {
if ((DateTime.TryParse(args.Value, out dt) == false) || { </script> <html> 注意 上面的代碼使用的方法DateTime.TryParse是ASP.NET2.0提供的新方法. 過濾自由文本字段 過濾輸入,你需要使不安全的輸入不被當作代碼來對待.例如,你的程序使用戶不能讀取共享數(shù)據(jù)庫內(nèi)的數(shù)據(jù),你首先需要過濾數(shù)據(jù)使它們在輸出的時候沒有危險.使用HttpUtility.HtmlEncode方法先對輸入值進行編碼. 允許有限的輸入HTML代碼
<%@ Page Language="C#" ValidateRequest="false"%> { StringBuilder sb = new StringBuilder( sb.Replace("<b>", "<b>"); 驗證查詢字串的值 驗證查詢字串的長度,范圍,格式和類型.通常,你使用一個合并的正則表達式來完成以下任務: •約束輸入值 void Page_Load(object sender, EventArgs e)
驗證Cookie值 象查詢字串這樣被保存在Cookie里面的值很容易被用戶修改.同樣地驗證這些值的長度,范圍,格式和類型. 如果你的程序允許輸入文件名,文件地址或者文件存放路徑,你需要驗證它們的格式是否正確并且根據(jù)你的程序?qū)嶋H情況它指向一個有效的位置.如果此步驗證失敗,你的程序可能會被錯誤地要求訪問文件. 驗證文件路徑 為了避免你的程序被用戶利用來訪問文件,防止接受用戶編寫代碼輸入的文件或者文件路徑.例如 : •如果你接受輸入文件名,使用System.IO.Path.GetFileName方法來取得文件的全稱 使用MapPath方法防止跨應用程序的映射 如果你使用MapPath方法在服務器上映射一個提供的虛擬目錄到一個物理目錄,使用Request.MapPath方法的一個帶bool參數(shù)的重載版本來防止跨應用程序的映射.下面是此項技術(shù)的示例代碼 : try
} 最終的false參數(shù)將會防止跨應用程序的映射.這意味著用戶不允許使用".."這樣的語法提供一個不在你所指定的虛擬目錄里面的非法路徑. 如果你使用服務器控件,你可以使用Control.MapPathSecure方法獲取虛擬目錄對應的實際目錄地址. Control.MapPathSecure方法在訪問一個非授權(quán)的文件時拋出一個HttpException的異常.需要更多信息,請參看.NET Framework文檔中的Control.MapPathSecure方法介紹. 使用代碼訪問安全機制限制文件輸入輸出 管理員可以通過設置程序使它的可信度為"中"來限制程序向它所在的虛擬目錄讀寫文件的能力..NET代碼安全機制可以保證程序在它所在的虛擬目錄之外沒有任何的文件訪問權(quán)利. 要設置一個應用程序的信任度為"中",可以在Web.config或者Machine.config文件中加入: <trust level = "Medium" /> 驗證URL 你可以用象下面的這樣的正則表達式來對URL進行特征匹配. ^(?:http|https|ftp)://[a-zA-Z0-9\.\-]+(?:\:\d{1,5})?(?:[A-Za-z0-9\.\;\:\@\&\=\+\$\,\?/]|%u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2})*$ 這只是約束輸入的格式,不驗證它是否在應用程序可接受的范圍內(nèi).你應該驗證它是否在你的程序的上下文中有效.例如,您的應用程序是否跟你指定的服務器進行通訊? 第三步.對不安全代碼進行編碼 如果您輸入文本輸入到一個網(wǎng)頁,使用HttpUtility.HtmlEncode方法對它進行編碼.如果這些文來自于用戶輸入,數(shù)據(jù)庫或者一個本地文件,請確保總是這樣做. 同樣地,如果您書寫的URL里面包含不安全的字符因為他們來自于用戶輸入內(nèi)容,數(shù)據(jù)庫等,使用HttpUtility.UrlEncode方法進行編碼. 為了防止存儲數(shù)據(jù)前編碼可能會使存儲的數(shù)據(jù)受到破壞,請確保在將它們顯示出來時盡可能后面的步驟將它們編碼. 使用HtmlEncode對不安全的輸出編碼 HtmlEncode對HTML標記置換成特殊含文的字符串來表示這些符號而又讓瀏覽器不把它們當作HTML標記來解釋處理.比如."<"被置換成< " (冒號) 被替換成" 這些標記被顯示成無害的文本. <%@ Page Language="C#" ValidateRequest="false" %> <script runat="server"> <html xmlns="http://www.w3.org/1999/xhtml" > 查看HTML編碼的效果,請建立一個虛擬目錄將前述的文件放進去,運行此頁面,在文本框中輸入一些HTML代碼,點擊提交按鈕.例如,下面的輸入被當作普通文本來顯示. Run script and say hello <script>alert('hello');</script> 如果你移除調(diào)用HtmlEncode方法,簡單地輸入文本的內(nèi)容,瀏覽器會執(zhí)行代碼并彈出一個提示框. 使用UrlEncode 方法對不安全的URL地址進行編碼 如果你需要獲取有用戶輸入部分的URL參數(shù),這可能帶來一定的安全風險,使用HttpUtility.UrlEncode方法對這個地址字符串編碼. HttpUtility.UrlEncode(urlString); 第四步.對SQL語句使用命令參數(shù)方式. 為了避免注入式攻擊請使用SQL的參數(shù)方式.參數(shù)(Parameters)集合提供類型檢測和長度檢測.如果你使用參數(shù)集合,輸入的內(nèi)容將被當作文本值來對待,數(shù)據(jù)庫不會執(zhí)行包含在其中的代碼.使用參數(shù)集方式的一個額外的好處是,你可以嚴格限定輸入的類型和長度.如果輸入型超出范圍將會觸發(fā)異常. 當調(diào)用一個存儲過程時使用參數(shù)集 下面的代碼片段演示了在調(diào)用存儲過程時使用參數(shù)集的例子. SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", 在創(chuàng)建你自己的SQL語句時使用參數(shù)集. 如果你不能使用存儲過程,你仍然可以使用參數(shù)集,請看下面的代碼. SqlDataAdapter myCommand = new SqlDataAdapter( 第五步.驗證ASP.NET的錯誤信息沒有被返回到客戶端 你可以使用<customErrors>元素來配置客戶端,一般的錯誤信息應該被程序錯誤檢測機制返回到客戶端. 請確認已經(jīng)更改web.config中的mode屬性為"remoteOnly",下面是示例. <customErrors mode = "remoteOnly"> 安在裝了一個ASP.NET 的程序之后,你可以按照如下設定指定客戶端的錯誤信息頁面。 <customErrors mode = "on" defaultRedirect = "YourErrorPage.htm"> |