楊 義 楊玉龍 張?zhí)烊?李 帥
(貴州航天計量測試技術(shù)研究所,貴州 貴陽 550009)
B/S(Browser/Server)網(wǎng)絡(luò)架構(gòu)的出現(xiàn),使得用戶只需要一臺能上網(wǎng)的電腦,就可以方便地在任何地方進行操作而不用安裝任何專門的軟件,但是隨之而來的安全問題不斷出現(xiàn)。最常見的就是SQL注入攻擊,之所以SQL注入攻擊如此常見,是因為它不需要攻擊者有很深入的編程功底,只要能熟練使用SQL語言即可。SQL注入可以導(dǎo)致數(shù)據(jù)庫系統(tǒng)中的普通用戶竊取機密數(shù)據(jù)、進行權(quán)限提升等,具有很強的破壞性。
結(jié)構(gòu)化查詢語言(Structured Query Language)簡稱SQL,是一種用來和數(shù)據(jù)庫交互的腳本語言,現(xiàn)今幾大主流數(shù)據(jù)庫都使用SQL語言。目前易受到SQL注入攻擊的兩大系統(tǒng)平臺組合是:SQL Server+ASP和MySQL+PHP,SQL Server和MySQL作為關(guān)系型數(shù)據(jù)庫,均采用SQL語言;ASP與PHP作為服務(wù)器端腳本語言,服務(wù)器端腳本程序是存在漏洞的,SQL注入攻擊就是因此而存在的。而使用SQL Server+.NET系統(tǒng)平臺組合相對安全些,因為.NET Framework開發(fā)提供了一系列的安全措施,如:.NET加密技術(shù),.NET的基于角色的安全技術(shù)。
SQL注入問題受到開發(fā)者的廣泛關(guān)注,2011年朱輝等提出了使用存儲過程的方法可有效防止SQL注入攻擊,但是沒給出存儲過程如何防止SQL注入的具體分析[3]。本文具體分析了存儲過程可有效解決SQL注入問題,并指出其本質(zhì)。同時提出了幾點.NET開發(fā)中的安全措施,可以很大程度上增強系統(tǒng)的安全性。
2002年,Chris Anley將SQL注入定義為:攻擊者通過在查詢操作中插入一系列的SQL語句到應(yīng)用程序中來操作數(shù)據(jù)。SQL注入攻擊的基本思想:通過向用戶輸入的信息中注入一些額外的特殊字符或者SQL語句,使系統(tǒng)服務(wù)器端構(gòu)造出來的SQL語句在執(zhí)行時改變了查詢條件,或者附帶執(zhí)行了攻擊者想要執(zhí)行的SQL語句。由此,攻擊者獲得數(shù)據(jù)庫的操作權(quán)限,或者根據(jù)程序返回的結(jié)果,獲得一些想知道的數(shù)據(jù)。
SQL注入主要是從SQL的語法中基于數(shù)據(jù)的應(yīng)用程序存在的漏洞而存在的,因此而導(dǎo)致SQL注入攻擊具有廣泛性。理論上說,SQL注入攻擊對于所有基于SQL語言標(biāo)準(zhǔn)的數(shù)據(jù)庫軟件都是有效的。下面給出一個簡單的SQL注入攻擊示例:
我們在經(jīng)常使用某個系統(tǒng)或需要登錄網(wǎng)站時,會通過表單的方式,提交自己的用戶名(username)和密碼(password),這時用戶名和密碼會被傳遞到Web服務(wù)器,在Web服務(wù)器端會進行有關(guān)SQL語句的重構(gòu),然后將重構(gòu)的SQL傳遞給數(shù)據(jù)庫服務(wù)器,在服務(wù)器端對SQL語句進行解析,返回查詢結(jié)果,以此來判斷是否允許登錄。
一般在Web服務(wù)器端構(gòu)造如下SQL查詢語句:
select count(0)from user where username='"+username+"'and password='"+password+"'
假設(shè)數(shù)據(jù)庫中存在用戶“admin,123”,即用戶名username為admin,密碼password為123,系統(tǒng)會對用戶名進行查詢,判斷是否存在該用戶名的用戶。但是,對于惡意攻擊者來說不會這么輸入,由于惡意攻擊者不知道用戶名和密碼,通常會提交惡意數(shù)據(jù),如:username=admin,password='321'or'1'='1'使得服務(wù)器構(gòu)造的SQL查詢語句變成select count(0)from admin where username='admin'and password='321'or'1'='1'。
因為'1'='1'恒為真,攻擊者就可以繞過對密碼的驗證,只驗證用戶名,圖1是SQL注入攻擊的實例圖。
圖1 SQL注入攻擊
圖中顯示了一般情況下的SQL注入攻擊過程。為了獲取更多的數(shù)據(jù)信息,攻擊者會通過SQL的深層次注入攻擊,在攻擊中在數(shù)據(jù)庫中添加自己的賬戶。
對于.NET開發(fā)初學(xué)者來說,很多人還停留在直接使用SQL語句訪問數(shù)據(jù)庫或者對數(shù)據(jù)庫中的數(shù)據(jù)進行修改。這就給善于SQL注入攻擊的攻擊者帶來了機會,目前對于SQL注入攻擊的研究已比較深入。一般的SQL注入攻擊防范方法總結(jié)如下:
2.2.1 WEB服務(wù)器的安全配置
(1)修改或者去掉WEB服務(wù)器上默認(rèn)的一些危險命令,例如服務(wù)器安裝之后的一些默認(rèn)用戶名和賬戶;
(2)屏蔽一些出錯信息;
(3)配置目錄的權(quán)限,分情況設(shè)置訪問目錄的權(quán)限,盡量不給寫目錄權(quán)限。
2.2.2 數(shù)據(jù)庫的安全配置
(1)修改數(shù)據(jù)庫的初始設(shè)置,修改或者去掉數(shù)據(jù)庫系統(tǒng)安裝之后產(chǎn)生的默認(rèn)登錄賬戶;
(2)及時升級數(shù)據(jù)庫;
(3)限定WEB應(yīng)用程序連接數(shù)據(jù)庫的用戶權(quán)限。
2.2.3 過濾特殊字符
(1)替換或刪除敏感字符、字符串;
(2)使用變量代替字串,建立SQL查詢,因為變量不是可以執(zhí)行的腳本。
除了以上基本的防范措施,在系統(tǒng)開發(fā)中,使用存儲過程來實現(xiàn)對數(shù)據(jù)庫中數(shù)據(jù)的查詢、刪除、更新等操作將是更有效的防止SQL注入攻擊方法。
存儲過程是建立在數(shù)據(jù)庫服務(wù)器端的SQL語句與部分控制流語句的預(yù)編譯集合,通過將某些關(guān)于數(shù)據(jù)庫操作的語言集中,交給SQL數(shù)據(jù)庫服務(wù)器來完成特定的任務(wù)。
存儲過程能有效提高系統(tǒng)的性能,主要是因為存儲過程在經(jīng)過第一次執(zhí)行后,會把查詢計劃保留在內(nèi)存中,以后在調(diào)用時,就無須進行編譯,直接調(diào)用該存儲過程。存儲過程具有以下三個方面的優(yōu)點:
(1)通過本地存儲、代碼預(yù)編譯和緩存技術(shù)實現(xiàn)高性能的數(shù)據(jù)操作;
(2)通過通用編程結(jié)構(gòu)和過程重用實現(xiàn)編程框架;
(3)通過隔離和加密的方法提高了數(shù)據(jù)庫的安全性。
存儲過程如何防止SQL注入攻擊,以身份驗證為例:
create procedure sp_getAdmin
(@adminName varchar(20),
@adminPwd varchar(50))
as
select count(0)from admin where adminName=@admin-Name and adminPwd=@adminPwd
go
在這個存儲過程中可以看到有兩個輸入?yún)?shù)@admin-Name和@adminPwd,數(shù)據(jù)類型都為varchar,這里應(yīng)用SQL注入攻擊中常用的方法,在登錄驗證中提交adminName為admin'--,adminPwd為123。如果不用存儲過程,驗證語句為:select count(0)from admin where adminName='admin'--'and adminPwd='123',這時密碼adminPwd參數(shù)因為“--”被解釋為注釋語句,從而在數(shù)據(jù)庫服務(wù)器端就只對用戶名進行驗證,而不對密碼進行驗證。
上面@adminName與@adminPwd為存儲過程參數(shù),主要用于在存儲過程和調(diào)用存儲過程的應(yīng)用程序或者工具之間傳輸數(shù)據(jù)。輸入?yún)?shù)用于調(diào)用方法的數(shù)據(jù)值傳遞到存儲過程,輸出參數(shù)用于存儲過程將數(shù)值或游標(biāo)變量傳遞回調(diào)用方,它們被預(yù)先作為獨立的數(shù)據(jù)體與SQL語句交互。
在上述sp_getAdmin存儲過程中,輸入?yún)?shù)@admin-Name和@adminPwd被當(dāng)成兩個獨立的數(shù)據(jù)體和SQL語句交互,而不是與一般的SQL語句一樣,將傳進的參數(shù)與SQL語句重組。驗證過程中,admin'--作為一個字符串傳遞給參數(shù)@username,123也作為一個字符串傳遞給參數(shù)@password。存儲過程中的SQL查詢語句不會重新組合為:select count(0)from admin where adminName='admin'--'and admin-Pwd='123',也就是“--”不會將后面的SQL語句注釋掉,“ad-min'--”是一個整體。
因此存儲過程驗證用戶名和密碼,是有效的身份驗證方法,在高效率訪問數(shù)據(jù)庫的同時,解決了SQL Injection攻擊。但是使用了存儲過程實現(xiàn)數(shù)據(jù)庫操作之后,并不等于SQL注入攻擊從此不會再出現(xiàn)。要使SQL注入攻擊成為不可能,最終取決于服務(wù)器端調(diào)用存儲過程的方式。針對不同的安全級別需求,還可以使用EXECUTE AS子句設(shè)定存儲過程的安全上下文。
跨站腳本攻擊(Cross Site Script Execution,XSS)指攻擊者利用網(wǎng)頁漏洞向客戶端注入腳本代碼,然后這些代碼被發(fā)送到受信任的客戶端上并被瀏覽器解釋執(zhí)行,攻擊者利用這些代碼盜取用戶資料或利用用戶身份對訪問者進行病毒侵害。代碼本身多用HTML和JavaScript編寫,但也可能擴展到VBScript、ActiveX,或其它瀏覽器支持的技術(shù)。根據(jù)形成原因的不同,跨站腳本攻擊可以分為三種攻擊類型,分別是反射型XSS攻擊、存儲型XSS攻擊和DOM型XSS攻擊[5]。
為有效防止跨站腳本攻擊,微軟在ASP.NET 1.1之后的版本中都引入了對提交表單自動檢測是否存在XSS的能力,但是很多程序員沒意識到。當(dāng)程序出現(xiàn)類似于HttpRequest-ValidationException或者“A potentially dangerous Request.Form value was detected from the client”的時候,很多程序員通過在ASP.NET頁面的page中或者web.config配置文件中設(shè)置validateRequest=false來禁用這個特性,以達(dá)到解決問題的目的。但是這樣做會使得ASP.NET的自動檢測XSS功能失效,失去了安全保護措施。在.NET開發(fā)中,每一個標(biāo)記的屬性都有其特有的用處,在不了解的情況下,不要輕易修改。
使用存儲過程加密技術(shù),使得非系統(tǒng)維護者,無法修改數(shù)據(jù)庫服務(wù)器中的存儲過程。對于一般的企業(yè),其數(shù)據(jù)庫服務(wù)器是托管的或租用的,這樣存在一個安全隱患,如果非法用戶通過其他手段登上了其SQL Server服務(wù)器,或通過注入得到了存儲過程,然后將存儲過程中的業(yè)務(wù)邏輯等修改,如果在此前數(shù)據(jù)庫未做備份那將造成不可估量的損失。對存儲過程加密的示例:
create procedure sp_getAdmin
(@adminName varchar(20),
@adminPwd varchar(50))with encryption
as
select count(0)from admin where adminName=@admin-Name and adminPwd=@adminPwd
go
需要注意的是,應(yīng)先備份原始的存儲過程,再進行加密,同時在生產(chǎn)環(huán)境前需完成加密。
系統(tǒng)管理員密碼加密是指在進行密碼比對時,會通過把用戶輸入的密碼與數(shù)據(jù)庫中事先加密好的系統(tǒng)管理員密碼進行比較,從而驗證用戶是否合法。下面就是ASP.NET中常用的兩種Hash算法MD5和SHA1相關(guān)類[6]:
MD5相關(guān)類:
System.Security.Cryptography.MD5
System.Security.Cryptography.MD5CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPassword-ForStoringInConfigFile(strSource,"MD5")
SHA1相關(guān)類:
System.Security.Cryptography.SHA1
System.Security.Cryptography.SHA1CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPassword-ForStoringInConfigFile(strSource,"SHA1")
在ASP.NET類中,對于加密算法的實現(xiàn)過程我們無需了解,只要我們知道如何使用就可以了。以下示例是使用MD5算法對管理員密碼進行Hash處理,然后向數(shù)據(jù)庫的管理員表中插入密碼加密后的信息記錄:insert into admin values('Zhang san', upper(right(sys.fn_varBinToHexStr(hashbytes('MD5','123456')),32)))
在服務(wù)器端驗證用戶名和密碼:///
///驗證用戶名與密碼
///
public bool CheckUserPassword(string userName,string password)
{
SqlParameter[]paras=new SqlParameter[2];
paras[0]= new SqlParameter("adminName",user-Name);
paras[1]=new SqlParameter("adminPwd",FormsAuthentication.HashPasswordForStoringInConfigFile(password,"MD5"));
return 0 } .NET所支持的加密技術(shù)[7]分為對稱密碼算法和非對稱密碼算法。對稱密碼算法包含DES,RC2,Rijndael,TripleDES;非對稱密碼算法包括:Digital Signature Algorithm(DSA),RSA。 基于角色的安全會詢問某個用戶是不是處于指定角色中的問題。如果該實體處于該角色中,他就可以安全地訪問一個系統(tǒng)資源或者應(yīng)用程序特性。微軟在ASP.NET 2.0發(fā)行中加入了現(xiàn)成的安全憑證基礎(chǔ)結(jié)構(gòu),在憑證存儲中,每個用戶或角色僅限于應(yīng)用程序之內(nèi)。這樣就允許不同應(yīng)用程序使用一樣的憑證存儲而不會與彼此的用戶名或角色相沖突。 基于角色的安全技術(shù)實施步驟[8]: (1)組織好站點中的文件; (2)利用網(wǎng)站管理工具進行安全配置; (3)利用控件創(chuàng)建安全頁。 本文分析了SQL注入攻擊的原理和存儲過程如何防止SQL注入攻擊,并且指出.NET開發(fā)中的常用安全措施,對于.NET開發(fā)初學(xué)者有很好的安全引導(dǎo)作用,也為下一步應(yīng)用開發(fā)奠定了安全基礎(chǔ)。4.3 基于角色的安全
5 總結(jié)