關於sql注入的危害在這裡就不多做介紹了,相信大家也知道其中的厲害關係。這裡有一些sql注入的事件大家感興趣可以看一下。
防範sql注入的方法無非有以下幾種:
1.使用型別安全的SQL引數
2.使用引數化輸入儲存過程
3.使用引數集合與動態SQL
4.輸入濾波
5.過濾LIKE條款的特殊字元
…如果有遺漏的也歡迎園子的大大們指教。
Sample:
1 2 3 |
var Shipcity; ShipCity = Request.form ("ShipCity"); var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'"; |
上面是一個簡單的sql注入示例
使用者將被提示輸入一個市縣名稱。如果使用者輸入 Redmond,則查詢將由與下面內容相似的指令碼組成:
1 |
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond' |
但是,假定使用者輸入以下內容:
Redmond’; drop table OrdersTable–
此時,指令碼將組成以下查詢:
1 |
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--' |
分號 (;) 表示一個查詢的結束和另一個查詢的開始。雙連字元 (–) 指示當前行餘下的部分是一個註釋,應該忽略。如果修改後的程式碼語法正確,則伺服器將執行該程式碼。SQL Server 處理該語句時,SQL Server 將首先選擇 OrdersTable 中的所有記錄(其中 ShipCity 為 Redmond)。然後,SQL Server 將刪除 OrdersTable。
只要注入的 SQL 程式碼語法正確,便無法採用程式設計方式來檢測篡改。因此,必須驗證所有使用者輸入,並仔細檢查在您所用的伺服器中執行構造 SQL 命令的程式碼。本主題中的以下各部分說明了編寫程式碼的最佳做法。
始終通過測試型別、長度、格式和範圍來驗證使用者輸入。實現對惡意輸入的預防時,請注意應用程式的體系結構和部署方案。請注意,設計為在安全環境中執行的程式可能會被複制到不安全的環境中。以下建議應被視為最佳做法:
- 對應用程式接收的資料不做任何有關大小、型別或內容的假設。例如,您應該進行以下評估:
- 如果一個使用者在需要郵政編碼的位置無意中或惡意地輸入了一個 10 MB 的 MPEG 檔案,應用程式會做出什麼反應?
- 如果在文字欄位中嵌入了一個 DROP TABLE 語句,應用程式會做出什麼反應?
- 測試輸入的大小和資料型別,強制執行適當的限制。這有助於防止有意造成的緩衝區溢位。
- 測試字串變數的內容,只接受所需的值。拒絕包含二進位制資料、轉義序列和註釋字元的輸入內容。這有助於防止指令碼注入,防止某些緩衝區溢位攻擊。
- 使用 XML 文件時,根據資料的架構對輸入的所有資料進行驗證。
- 絕不直接使用使用者輸入內容來生成 Transact-SQL 語句。
- 使用儲存過程來驗證使用者輸入。
- 在多層環境中,所有資料都應該在驗證之後才允許進入可信區域。未通過驗證過程的資料應被拒絕,並向前一層返回一個錯誤。
- 實現多層驗證。對無目的的惡意使用者採取的預防措施對堅定的攻擊者可能無效。更好的做法是在使用者介面和所有跨信任邊界的後續點上驗證輸入。例如,在客戶端應用程式中驗證資料可以防止簡單的指令碼注入。但是,如果下一層認為其輸入已通過驗證,則任何可以繞過客戶端的惡意使用者就可以不受限制地訪問系統。
- 絕不串聯未驗證的使用者輸入。字串串聯是指令碼注入的主要輸入點。
- 在可能據以構造檔名的欄位中,不接受下列字串:AUX、CLOCK$、COM1 到 COM8、CON、CONFIG$、LPT1 到 LPT8、NUL 以及 PRN。
如果可能,拒絕包含以下字元的輸入。
輸入字元 | 在 Transact-SQL 中的含義 |
---|---|
; | 查詢分隔符。 |
‘ | 字元資料字串分隔符。 |
— | 註釋分隔符。 |
/* … */ | 註釋分隔符。伺服器不對 /* 和 */ 之間的註釋進行處理。 |
xp_ | 用於目錄擴充套件儲存過程的名稱的開頭,如 xp_cmdshell。 |
注:驗證輸入是最被常用和聯想到的,但是個人感覺這種方式不但程式碼顯得肥胖,而且效率不是很好
2.使用型別安全的 SQL 引數
SQL Server 中的 Parameters 集合提供了型別檢查和長度驗證。如果使用 Parameters 集合,則輸入將被視為文字值而不是可執行程式碼。使用 Parameters 集合的另一個好處是可以強制執行型別和長度檢查。範圍以外的值將觸發異常。以下程式碼段顯示瞭如何使用 Parameters 集合:
1 2 3 4 5 |
SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn); myCommand.SelectCommand.CommandType = CommandType.StoredProcedure; SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11); parm.Value = Login.Text; |
在此示例中,@au_id 引數被視為文字值而不是可執行程式碼。將對此值進行型別和長度檢查。如果 @au_id 值不符合指定的型別和長度約束,則將引發異常。
儲存過程如果使用未篩選的輸入,則可能容易受 SQL Injection 攻擊。例如,以下程式碼容易受到攻擊:
1 |
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure '" + Login.Text + "'", conn); |
如果使用儲存過程,則應使用引數作為儲存過程的輸入。
注:在鄙人現在的專案中,這種方法應用最為廣泛
3.在動態 SQL 中使用引數集合
如果不能使用儲存過程,您仍可使用引數,如以下程式碼示例所示:
1 2 3 4 5 |
SqlDataAdapter myCommand = new SqlDataAdapter( "SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn); SQLParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11); Parm.Value = Login.Text; |
注:和第二種雷同,這種方法是為了補充方法2存在,因為往往在很多時候業務簡單不需要用proc的時候,可以用這種方法
4.篩選輸入
篩選輸入可以刪除轉義符,這也可能有助於防止 SQL 注入。但由於可引起問題的字元數量很大,因此這並不是一種可靠的防護方法。以下示例可搜尋字串分隔符。
1 2 3 4 |
private string SafeSqlLiteral(string inputSQL) { return inputSQL.Replace("'", "''"); } |
注:Filtering Input有種類似方法1
5.LIKE 子句
請注意,如果要使用 LIKE 子句,還必須對萬用字元字元進行轉義:
1 2 3 |
s = s.Replace("[", "[[]"); s = s.Replace("%", "[%]"); s = s.Replace("_", "[_]"); |
注:針對like子句,在使用時的效率這裡就不多說了,總之要慎用了。
以上所有方法及其註釋高亮顯示部分,均為本人愚見,如果對方法有補充或者對高亮部分有不同意見的,歡迎大家給出意見,共同進步.