SQL隱碼攻擊(一)

weixin_34119545發表於2009-12-14
首先我想謝謝園子的朋友們,是你們提醒我寫內容有錯誤,記得曾經電子商務之資料儲存流程(五)裡面說到“選儲存過程+傳遞引數用SqlParameter是因為,除非是ADO.NET有漏洞,那麼就絕對不會發生SQL注入”。Keep Walking大哥也在關於防止sql注入的幾種手段(二)中舉出來一個例子說明我說的上句話是錯誤的。說實話當時我還是對SQL注入不是很瞭解,也沒有遇到過SQL注入,也不是很關心它。但是我想安全的問題我們一定要非常注意,於是這些時候花了一些時間來學習了SQL注入。

什麼是SQL注入

  可能大家還不是對SQL注入這個概念不是很清楚,簡單地說,SQL注入就是攻擊者通過正常的WEB頁面,把自己SQL程式碼傳入到應用程式中,從而通過執行非程式設計師預期的SQL程式碼,達到竊取資料或破壞的目的。

  當應用程式使用輸入內容來構造動態SQL語句以訪問資料庫時,會發生SQL注入攻擊。如果程式碼使用儲存過程,而這些儲存過程作為包含未篩選的使用者輸入的字串來傳遞,也會發生SQL注入。SQL注入可能導致攻擊者使用應用程式登陸在資料庫中執行命令。如果應用程式使用特權過高的帳戶連線到資料庫,這種問題會變得很嚴重。在某些表單中,使用者輸入的內容直接用來構造(或者影響)動態SQL命令,或者作為儲存過程的輸入引數,這些表單特別容易受到SQL注入的攻擊。而許多網站程式在編寫時,沒有對使用者輸入的合法性進行判斷或者程式中本身的變數處理不當,使應用程式存在安全隱患。這樣,使用者就可以提交一段資料庫查詢的程式碼,根據程式返回的結果,獲得一些敏感的資訊或者控制整個伺服器,於是SQL注入就發生了。

一般SQL隱碼攻擊

  在Web 應用程式的登入驗證程式中,一般有使用者名稱(username) 和密碼(password) 兩個引數,程式會通過使用者所提交輸入的使用者名稱和密碼來執行授權操作。我們有很多人喜歡將SQL語句拼接起來。例如:

  Select * from users where username =’ txtusername.Text ’ and  password =’ txtpassword.Text ’

  其原理是通過查詢users 表中的使用者名稱(username) 和密碼(password) 的結果來進行授權訪問, txtusername.Textmysqltxtpassword.Textmary,那麼SQL查詢語句就為:

  Select * from users where username =’ mysql ’ and  password  =’ mary ’

  如果分別給txtusername.Text txtpassword.Text值’ or ‘1’ = ‘1’ --abc那麼,SQL 指令碼直譯器中的上述語句就會變為:

  Select * from users where username =’’or  ‘1’ = ‘1’  -- and password =’abc’

  該語句中進行了兩個條件判斷,只要一個條件成立,就會執行成功。而'1'='1'在邏輯判斷上是恆成立的,後面的"--" 表示註釋,即後面所有的語句為註釋語句這樣我們就成功登入。即SQL注入成功.

  如果我們給txtusername.Text賦值為:’;drop table users--即:

  Select * from users where username =’’;drop table users-- and password =’abc’

  整個使用者表就沒有了,當然這裡要猜出資料表名稱。想想是多麼可怕的事情。

  好我想大家在這裡已經大致明白了一般SQL注入了,試想下您的登入程式會不會出現我上述的情況。

防範SQL注入

     那麼現在大家都在思考怎麼防範SQL隱碼攻擊了這裡給出一點個人的建議

1.限制錯誤資訊的輸出

  這個方法不能阻止SQL隱碼攻擊,但是會加大SQL隱碼攻擊的難度,不會讓注入者輕易得到一些資訊,讓他們任意破壞資料庫。SQL Server有一些系統變數,如果我們沒有限制錯誤資訊的輸出,那麼注入著可以直接從出錯資訊獲取,例如(假定這裡用的string即字元型別並可以發生SQL隱碼攻擊):http://www.xxx.com/showdetail.aspx?id=49 and user>0 這句語句很簡單,但卻包含了SQL Server特有注入方法的精髓,。首先看看它的含義:首先,前面的語句是正常的,重點在and user>0,我們知道,user是SQL Server的一個內建變數,它的值是當前連線的使用者名稱,型別為nvarchar。拿一個nvarchar的值跟int的數0比較,系統會先試圖將nvarchar的值轉成int型,當然,轉的過程中肯定會出錯,SQL Server的出錯提示是:將nvarchar”abc” 轉換資料型別為 int 的列時發生語法錯誤,呵呵,abc正是變數user的值,這樣,注入著就拿到了資料庫的使用者名稱。

  眾所周知,SQL Server的使用者sa是個等同Adminstrators許可權的角色,拿到了sa許可權,幾乎肯定可以拿到主機的Administrator了。上面的方法可以很方便的測試出是否是用sa登入,要注意的是:如果是sa登入,提示是將”dbo”轉換成int的列發生錯誤,而不是”sa”。

  當然注入者還可以輸入不同的資訊來得到他們想要的資訊 ,上面只是其中一個例子,所以我們要限制錯誤資訊的輸出,從而保護我們的資料庫資料,這裡我給出.NET限制錯誤資訊的方法:

  在Web.Config檔案中設定

  <customErrors mode="On" defaultRedirect="error.aspx">

  </customErrors>

  這樣當發生錯誤時候就不會講資訊洩露給外人。

2.限制訪問資料庫帳號的許可權

  對於資料庫的任何操作都是以某種特定身份和相應許可權來完成的,SQL語句執行前,在資料庫伺服器端都有一個使用者許可權驗證的過程,只有具備相應許可權的帳號才可能執行相應許可權內的SQL語句。因此,限制資料庫帳號許可權,實際上就阻斷了某些SQL語句執行的可能。不過,這種方法並不能根本解決SQL注入問題,因為連線資料庫的帳號幾乎總是比其他單個使用者帳號擁有更多的許可權。通過限制貼帳號許可權,可以防止刪除表的攻擊,但不能阻止攻擊者偷看別人的資訊。

3.引數化使用命令

  引數化命令是在SQL文字中使用佔位符的命令。佔位符表示需要動態替換的資料,它們通過Command物件Parameters集合來傳送。能導致攻擊的SQL程式碼可以寫成:

Select * from employee where userID=@userID;

  如果使用者輸入: 09105022OR ‘1’=’1,將得不到何記錄,因為沒有一個使用者ID與文字框中輸入的’ 09105022’OR ‘1’=’1’相等。引數化命令的語法隨提供程式的不同略有差異。對於SQL SERVER提供程式,引數化命令使用命名的佔位符(具有唯一的名字),而對於OLE DB提供程式,每個硬編碼的值被問號代替。使用OLE DB提供程式時,需要保證引數的順序和它們出現在SQL字串中的位置一致。SQL SERVER提供程式沒有這樣的需求,因為它們用名字和佔位符匹配。

4.呼叫儲存過程

  儲存過程是儲存在資料庫伺服器上的一系列SQL程式碼,儲存過程與函式相似,有良好的邏輯封裝結構,可以接收和返回資料。使用儲存過程可以使程式碼更易於維護,因為對儲存過程的更改不會導致應用程式的重新編譯,使用儲存過程還可以節省頻寬,提高應用程式效能。因為儲存過程是儲存在資料庫服務端的獨立的封裝體,呼叫儲存過程可以保證應用程式只執行儲存過程中的固定程式碼,從而杜絕SQL語句注入的可能。結合上述所講的引數化命令,可以實現SQL程式碼可以實現的任何功能,並進一步提高應用程式的安全等級。

  今天就寫到這吧,後面還有一些防範的方法,可能更要實用一些,就在後面的文章介紹吧

相關文章