NET防SQL隱碼攻擊方法

iDotNetSpace發表於2009-07-09
SQL語句

利用SqlCommand傳引數的方法:

string strSQL="SELECT * FROM [user] WHERE user_id=@id";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = strSQL;
cmd.Parameters.Add("@id",SqlDbType.VarChar,20).Value=Request["id"].ToString();

過濾禁止執行法:

            ///
            /// 過濾SQL語句,防止注入
            ///

            ///
            /// 0 - 沒有注入, 1 - 有注入
            public int filterSql(string sSql)
            { 
                int srcLen, decLen = 0;
                sSql = sSql.ToLower().Trim();
                srcLen = sSql.Length;
                sSql = sSql.Replace("exec", "");
                sSql = sSql.Replace("delete", "");
                sSql = sSql.Replace("master", "");
                sSql = sSql.Replace("truncate", "");
                sSql = sSql.Replace("declare", "");
                sSql = sSql.Replace("create", "");
                sSql = sSql.Replace("xp_", "no");
                decLen = sSql.Length;
                if (srcLen == decLen) return 0; else return 1;         
            }

儲存過程 

因為在儲存過程中就可以設定變數的型別,所以也無需對資料做任何操作


漏洞演示:
http://xxx.xxx.xxx.xxx/xxx.asp?id=17;DROP TABLE D99_Tmp;CREATE TABLE D99_Tmp(subdirectory VARCHAR(100),depth VARCHAR(100),[file] VARCHAR(100))

禁止後使用SQL 語句中就不能出現“exec, master, delete, truncate, declare, create, xp_”這些字元。

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

SQL隱碼攻擊是非常令人討厭的安全漏洞,是所有的web開發人員,不管是什麼平臺,技術,還是資料層,需要確信他們理解和防止的東西。不幸的是,開發人員往往不集中花點時間在這上面,以至他們的應用,更糟糕的是,他們的客戶極其容易受到攻擊。

Michael Sutton 最近發表了一篇非常發人深省的帖子,講述在公共網上這問題是多麼地普遍。他用Google的Search API建了一個C#的客戶端程式,尋找那些易受SQL 注入攻擊的網站。其步驟很簡單:

尋找那些帶查詢字串的網站(例如,查詢那些在URL裡帶有 "id=" 的URL) 
給這些確定為動態的網站傳送一個請求,改變其中的id=語句,帶一個額外的單引號,來試圖取消其中的SQL語句(例如,如 id=6' ) 
分析返回的回覆,在其中查詢象"SQL" 和"query"這樣的詞,這往往表示應用返回了詳細的錯誤訊息(這本身也是很糟糕的) 
檢查錯誤訊息是否表示傳送到SQL伺服器的引數沒有被正確加碼(encoded),如果如此,那麼表示可對該網站進行SQL隱碼攻擊 
對通過Google搜尋找到的1000個網站的隨機取樣測試,他檢測到其中的11.3%有易受SQL隱碼攻擊的可能。這非常,非常地可怕。這意味著黑客可以遠端利用那些應用裡的資料,獲取任何沒有hashed或加密的密碼或信用卡資料,甚至有以管理員身份登陸進這些應用的可能。這不僅對開發網站的開發人員來說很糟糕,而且對使用網站的消費者或使用者來說更糟糕,因為他們給網站提供了資料,想著網站是安全的呢。

那麼SQL隱碼攻擊到底是什麼玩意?

有幾種情形使得SQL隱碼攻擊成為可能。最常見的原因是,你動態地構造了SQL語句,卻沒有使用正確地加了碼(encoded)的引數。譬如,考慮這個SQL查詢的編碼,其目的是根據由查詢字串提供的社會保險號碼(social security number)來查詢作者(Authors):


Dim SSN as String
Dim SqlQuery as String

SSN = Request.QueryString("SSN")
SqlQuery = "SELECT au_lname, au_fname FROM authors WHERE au_id = '" + SSN + "'" 

如果你有象上面這個片斷一樣的SQL編碼,那麼你的整個資料庫和應用可以遠端地被黑掉。怎麼會呢?在普通情形下,使用者會使用一個社會保險號碼來訪問這個網站,編碼是象這樣執行的:


' URL to the page containing the above code
http://mysite.com/listauthordetails.aspx?SSN=172-32-9999

' SQL Query executed against the database 
SELECT au_lname, au_fname FROM authors WHERE au_id = '172-32-9999' 

這是開發人員預期的做法,通過社會保險號碼來查詢資料庫中作者的資訊。但因為引數值沒有被正確地加碼,黑客可以很容易地修改查詢字串的值,在要執行的值後面嵌入附加的SQL語句 。譬如,


' URL to the page containing the above code
http://mysite.com/listauthordetails.aspx?SSN=172-32-9999';DROP DATABASE pubs --

' SQL Query executed against the database 
SELECT au_lname, au_fname FROM authors WHERE au_id = '';DROP DATABASE pubs -- 
注意到沒有,我可以在SSN查詢字串值的後面新增" ';DROP DATABASE pubs -- ",通過 ";"字元來終止當前的SQL語句,然後新增了我自己的惡意的SQL語句,然後把語句的其他部分用"--"字串註釋掉。因為我們是手工在編碼裡構造SQL語句,我們最後把這個字串傳給了資料庫,資料庫會先對authors表進行查詢,然後把我們的pubs資料庫刪除。"砰(bang)"的一聲,資料庫就沒了!

萬一你認為匿名黑客刪除你的資料庫的結果很壞,但不幸的是,實際上,這在SQL隱碼攻擊所涉及的情形中算是比較好的。一個黑客可以不單純摧毀資料,而是使用上面這個編碼的弱點,執行一個JOIN語句,來獲取你資料庫裡的所有資料,顯示在頁面上,允許他們獲取使用者名稱,密碼,信用卡號碼等等。他們也可以新增 UPDATE/INSERT 語句改變產品的價格,新增新的管理員賬號,真的搞砸你(screw up your life)呢。想象一下,到月底檢查庫存時,發現你庫房裡的實際產品數與你的帳目系統(accounting system)彙報的數目有所不同。。。

那該如何保護你自己?

SQL隱碼攻擊是你需要擔心的事情,不管你用什麼web程式設計技術,再說所有的web框架都需要擔心這個的。你需要遵循幾條非常基本的規則:

1) 在構造動態SQL語句時,一定要使用類安全(type-safe)的引數加碼機制。大多數的資料API,包括ADO和ADO.NET,有這樣的支援,允許你指定所提供的引數的確切型別(譬如,字串,整數,日期等),可以保證這些引數被恰當地escaped/encoded了,來避免黑客利用它們。一定要從始到終地使用這些特性。 

例如,在ADO.NET裡對動態SQL,你可以象下面這樣重寫上述的語句,使之安全: 

Dim SSN as String = Request.QueryString("SSN")

Dim cmd As new SqlCommand("SELECT au_lname, au_fname FROM authors WHERE au_id = @au_id")
Dim param = new SqlParameter("au_id", SqlDbType.VarChar)
param.Value = SSN
cmd.Parameters.Add(param) 
這將防止有人試圖偷偷注入另外的SQL表示式(因為ADO.NET知道對au_id的字串值進行加碼),以及避免其他資料問題(譬如不正確地轉換數值型別等)。注意,VS 2005內建的TableAdapter/DataSet設計器自動使用這個機制,ASP.NET 2.0資料來源控制元件也是如此。 

一個常見的錯誤知覺(misperception)是,假如你使用了儲存過程或ORM,你就完全不受SQL隱碼攻擊之害了。這是不正確的,你還是需要確定在給儲存過程傳遞資料時你很謹慎,或在用ORM來定製一個查詢時,你的做法是安全的。 

2) 在部署你的應用前,始終要做安全審評(security review)。建立一個正式的安全過程(formal security process),在每次你做更新時,對所有的編碼做審評。後面一點特別重要。很多次我聽說開發隊伍在正式上線(going live)前會做很詳細的安全審評,然後在幾周或幾個月之後他們做一些很小的更新時,他們會跳過安全審評這關,推說,"就是一個小小的更新,我們以後再做編碼審評好了"。請始終堅持做安全審評。

3) 千萬別把敏感性資料在資料庫裡以明文存放。我個人的意見是,密碼應該總是在單向(one-way )hashed過後再存放,我甚至不喜歡將它們在加密後存放。在預設設定下,ASP.NET 2.0 Membership API 自動為你這麼做,還同時實現了安全的SALT 隨機化行為(SALT randomization behavior)。如果你決定建立自己的成員資料庫,我建議你檢視一下我們在這裡發表的我們自己的Membership provider的原始碼。同時也確定對你的資料庫裡的信用卡和其他的私有資料進行了加密。這樣即使你的資料庫被人入侵(compromised)了的話,起碼你的客戶的私有資料不會被人利用。

4) 確認你編寫了自動化的單元測試,來特別校驗你的資料訪問層和應用程式不受SQL隱碼攻擊。這麼做是非常重要的,有助於捕捉住(catch)"就是一個小小的更新,所有不會有安全問題"的情形帶來的疏忽,來提供額外的安全層以避免偶然地引進壞的安全缺陷到你的應用裡去。

5) 鎖定你的資料庫的安全,只給訪問資料庫的web應用功能所需的最低的許可權。如果web應用不需要訪問某些表,那麼確認它沒有訪問這些表的許可權。如果web應用只需要只讀的許可權從你的account payables表來生成報表,那麼確認你禁止它對此表的 insert/update/delete 的許可權。



類別:經驗交流-語言 | 瀏覽(56)     網友評論:1 ztf704 - 2007年04月04日 13:18 -- 獲得MS SQL的版本號 
execute master..sp_msgetversion 

-- 得到硬碟檔案資訊 
-- 引數說明:目錄名,目錄深度,是否顯示檔案 
execute master..xp_dirtree c: 
execute master..xp_dirtree c:,1 
execute master..xp_dirtree c:,1,1 

-- 列出伺服器上安裝的所有OLEDB提供的程式 
execute master..xp_enum_oledb_providers 

-- 列出伺服器上安裝的所有內碼表 
execute master..xp_enumcodepages 

-- 列出伺服器上配置的dsn 
execute master..xp_enumdsn 

-- 列出sql server錯誤日誌列表,最後更新時間 
execute master..xp_enumerrorlogs 

-- 列出伺服器上所有windows本地組 
execute master..xp_enumgroups 

-- 檢測檔案存在性 
execute master..xp_fileexist 'c:/a.bak' 
declare @flag int 
exec master..xp_fileexist 'c:/abc.bak',@flag out 
if @flag=1 
begin 
print 'exist' 
end 
else 
begin 
print 'no exist' 
end 

-- 列出伺服器上固定驅動器,以及每個驅動器的可用空間 
execute master..xp_fixeddrives 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-608729/,如需轉載,請註明出處,否則將追究法律責任。

相關文章