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