葛昕,楊小東,岳敏楠
(1.上海理工大學(xué)網(wǎng)絡(luò)中心,上海200093;2.上海理工大學(xué)研究生部,上海200093)
基于.NET的信息系統(tǒng)SQL注入防御研究*
葛昕1,楊小東2,岳敏楠1
(1.上海理工大學(xué)網(wǎng)絡(luò)中心,上海200093;2.上海理工大學(xué)研究生部,上海200093)
使用.NET開(kāi)發(fā)信息系統(tǒng)是近年來(lái)高校廣泛采用的一種形式,因此針對(duì)它的攻擊也日益增多,其中最為嚴(yán)重的SQL注入攻擊,可以徹底摧毀數(shù)據(jù)庫(kù),并給攻擊者打開(kāi)登錄系統(tǒng)的后門。本文以上海理工大學(xué)研究生信息系統(tǒng)和Web網(wǎng)站為研究樣本,分析了流行的注入攻擊代碼,給出了修復(fù)此攻擊的方法,并設(shè)計(jì)了一套行之有效的SQL注入防御系統(tǒng),此方法在實(shí)際應(yīng)用中得到了證明。
.NET;SQL注入;存儲(chǔ)過(guò)程;信息系統(tǒng)
隨著網(wǎng)絡(luò)基礎(chǔ)建設(shè)日趨成熟,信息系統(tǒng)的應(yīng)用也越來(lái)越廣泛,而同時(shí)產(chǎn)生的問(wèn)題就是網(wǎng)絡(luò)攻擊的不斷出現(xiàn)。在眾多的攻擊手段中,SQL注入式攻擊是較易掌握并容易獲得成功的一種攻擊方式,特別是一些自動(dòng)化的SQL注入工具的出現(xiàn),如NBSI2、DOMAIN3等,更是使得許多動(dòng)態(tài)站點(diǎn)成為SQL攻擊下的犧牲品。而造成這種情況的一個(gè)主要原因就是程序員在編寫程序時(shí)沒(méi)有對(duì)用戶提交數(shù)據(jù)的合法性進(jìn)行驗(yàn)證,從而使得程序存在隱患。SQL注入是從正常的WWW端口訪問(wèn),表面看起來(lái)跟一般的Web頁(yè)面訪問(wèn)沒(méi)什么區(qū)別,這類攻擊屬于應(yīng)用層攻擊,所以以往的基于包過(guò)濾法、基于狀態(tài)檢測(cè)法等完全無(wú)效。要解決SQL注入攻擊問(wèn)題,就必須在應(yīng)用層進(jìn)行充分的防范來(lái)確保系統(tǒng)的安全。上海理工大學(xué)研究生部的多個(gè)應(yīng)用系統(tǒng)都采用了.NET+SQL作為開(kāi)發(fā)環(huán)境,本文就是以此為平臺(tái)進(jìn)行研究。
SQL注入攻擊的具體過(guò)程為:發(fā)現(xiàn)SQL注入位置;判斷后臺(tái)數(shù)據(jù)庫(kù)類型;確定XP_CMDSHELL可執(zhí)行情況;發(fā)現(xiàn)Web虛擬目錄;上傳ASPX木馬;得到管理員權(quán)限。[1]發(fā)現(xiàn)SQL注入位置是整個(gè)攻擊的源頭,攻擊者將某些經(jīng)過(guò)精心構(gòu)造的特殊的SQL字符串插入到Web表單的輸入域,欺騙服務(wù)器執(zhí)行惡意的SQL命令,即可判斷出是否存在注入點(diǎn)。[2]SQL注入的手法相當(dāng)靈活,在注入時(shí)通過(guò)構(gòu)造巧妙的SQL語(yǔ)句,可以使系統(tǒng)錯(cuò)誤地授權(quán)給攻擊者,幫助其成功獲取想要的數(shù)據(jù),或者修改數(shù)據(jù),進(jìn)而在網(wǎng)站進(jìn)行掛馬操作。以下是近來(lái)最為流行的注入攻擊的存儲(chǔ)過(guò)程,其結(jié)果可以將數(shù)據(jù)庫(kù)中多數(shù)類似varchar字段的內(nèi)容修改為木馬地址來(lái)進(jìn)行系統(tǒng)掛馬。
DECLARE@T varchar(255),@C varchar(255)
DECLARE Table_Cursor CURSOR FOR//定義游標(biāo)
SELECTa.name,b.nameFROM sysobjectsa,syscolumnsb
WHERE a.id=b.id AND a.xtype=′u′AND(b.xtype =99 OR b.xtype=35 OR b.xtype=231 OR b.xtype=167) //當(dāng)表字段類型為ntext、text、xtype、nvarchar、varchar時(shí)
OPENTable_CursorFETCHNEXTFROM Table_Cursor INTO@T,@C
WHILE(@@FETCH_STATUS=0)
BEGIN
EXEC(′update[′+@T+′]set[′+@C+′]=rtrim (convert(varchar,[′+@C+′]))+′′<script src=http://掛馬網(wǎng)站地址/1.js></script>′′′)//將字段內(nèi)容修改為掛馬網(wǎng)站地址
FETCH NEXT FROM Table_Cursor INTO@T,@C
END
CLOSE Table_Cursor DEALLOCATE Table_Cursor
這種方式利用系統(tǒng)代碼中存在的漏洞進(jìn)行注入,先遍歷數(shù)據(jù)庫(kù)中某些特定字段類型,將記錄中該字段插入含有js文件的惡意script標(biāo)簽,即木馬的地址。雖然這些js文件的內(nèi)容不同,但是他們都嘗試?yán)靡呀?jīng)被修復(fù)的Microsoft產(chǎn)品的漏洞或者第三方ActiveX控件的漏洞。由于這些腳本被單獨(dú)存儲(chǔ),因此很容易被更新以利用客戶端更新的漏洞,也更容易按照不同瀏覽器來(lái)定制。對(duì)于這種破壞,我們只要采用類似注入攻擊的方法將注入代碼中間部分替換為如下代碼,運(yùn)行后即可將數(shù)據(jù)庫(kù)中的惡意代碼刪除。
DECLARE@str varchar(500)//聲明要替換的字符
set@str=′<script src=http://掛馬網(wǎng)站地址/1.js></ script>′//這里是你要替換的字符
OPEN Table_Cursor FETCH NEXT FROM Table_ Cursor INTO@T,@C
WHILE(@@FETCH_STATUS=0)
BEGIN
EXEC(′update[′+@T+′]set[′+@C+′]=replace (cast([′+@C+′]as varchar(8000)),′′′+@str+′′′,′′′′)′) //清除記錄內(nèi)容中含有的木馬地址
FETCH NEXT FROM Table_Cursor INTO@T,@C
END
為了能夠主動(dòng)地防御SQL注入攻擊,我們可以將所有傳入的SQL參數(shù)全部使用存儲(chǔ)過(guò)程來(lái)實(shí)現(xiàn),但對(duì)于一些已經(jīng)在使用的系統(tǒng)顯然不現(xiàn)實(shí),而且使用分頁(yè)存儲(chǔ)時(shí)如果進(jìn)行拼接字串來(lái)替換危險(xiǎn)字符仍會(huì)有漏洞。為了保護(hù)原有代碼不做修改,可以采用另一種方法,對(duì)傳入?yún)?shù)進(jìn)行過(guò)濾。本文設(shè)計(jì)了一個(gè)綜合防御系統(tǒng),包括三個(gè)部分:檢測(cè)模塊、過(guò)濾模塊和記錄模塊。檢測(cè)模塊用于檢測(cè)系統(tǒng)數(shù)據(jù)庫(kù)是否已受注入破壞,過(guò)濾模塊對(duì)所有要傳入的參數(shù)做SQL關(guān)鍵字符過(guò)濾,日志模塊用于對(duì)嘗試注入的攻擊進(jìn)行日志記錄,幫助管理員進(jìn)行日常安全性分析與維護(hù)。對(duì)于所有使用.NET+SQL構(gòu)造的信息系統(tǒng),只要將過(guò)濾模塊加載在所有要使用數(shù)據(jù)庫(kù)系統(tǒng)的頁(yè)面中即可實(shí)現(xiàn)對(duì)SQL注入的防御。以下只列出最為核心的過(guò)濾模塊和日志模塊中的關(guān)鍵代碼。
//判斷用戶請(qǐng)求字符是否含有SQL注入攻擊字符
private bool ProcessSqlStr(string Str)//Str為用戶提交數(shù)據(jù)
{bool ReturnValue=true;
try{if(Str.Trim()!="")
{string SqlStr="and|exec|insert|select |delete|update|count|*|chr|mid|master|truncate|char| declare";//用戶可自行定義過(guò)濾參數(shù)
string[]anySqlStr=SqlStr.Split(′|′);
foreach(string ss in anySqlStr)
{if(Str.ToLower().IndexOf(ss)>=0)
{ReturnValue=false;
break;}
}
}
}
catch{ReturnValue=false;}
return ReturnValue;
}
在服務(wù)器上建立一個(gè)文件夾AttackLog,創(chuàng)建日志文件log.aspx用于存放每天SQL攻擊操作產(chǎn)生的日志。以下為記錄日志部分核心代碼。
public partial class ErrorLog_Log:System.Web.UI.Page
{
protected void Page_Load(objectsender,EventArgse)
{
Log(HttpUtility.UrlDecode(Request["PreUrl"]));
}
private void Log(string url)
{
DateTime dt=DateTime.Now;
string fileName=Server.MapPath("/AttackLog") +"\Log"+dt.ToString("yyyy_MM_dd")+".log";
string content=dt.ToString()+","+Request. UserHostAddress+","+url+" ";
File.AppendAllText(fileName,content);
//Response.Redirect("/errorPage.htm l");
}
}
對(duì)于.NET開(kāi)發(fā)的信息系統(tǒng),被攻擊的根本原因還是程序編碼有漏洞,故在編寫程序時(shí),可以參考以下建議,加強(qiáng)程序代碼的安全性。
第一,在構(gòu)造動(dòng)態(tài)SQL語(yǔ)句時(shí),使用類安全的參數(shù)代碼機(jī)制。
第二,限制表單或查詢字符串輸入的長(zhǎng)度,這可以很大程度上增加攻擊者在SQL命令中插入有害代碼的難度。
第三,檢查用戶輸入的合法性,確信輸入的內(nèi)容只包含合法的數(shù)據(jù)。為了彌補(bǔ)客戶端驗(yàn)證機(jī)制脆弱的安全性,數(shù)據(jù)檢查在服務(wù)器端也需要執(zhí)行。
第四,在部署應(yīng)用前,對(duì)所有的編碼做安全審評(píng)。不把敏感數(shù)據(jù)在數(shù)據(jù)庫(kù)里以明文存放。敏感數(shù)據(jù)應(yīng)該在單向加密過(guò)后再存放。將用戶輸入的數(shù)據(jù)加密后,再與數(shù)據(jù)庫(kù)中保存的數(shù)據(jù)比較,相當(dāng)于對(duì)用戶輸入的數(shù)據(jù)進(jìn)行了“消毒”處理,用戶輸入的數(shù)據(jù)不再對(duì)數(shù)據(jù)庫(kù)有任何特殊的意義,從而也就防止了攻擊者注入SQL命令。
第五,檢查提取數(shù)據(jù)的查詢所返回的記錄數(shù)量。如果程序只要求返回一個(gè)記錄,但實(shí)際返回的記錄卻超過(guò)一行,那就當(dāng)作出錯(cuò)處理。
第六,只給訪問(wèn)數(shù)據(jù)庫(kù)的Web應(yīng)用功能所需的最低權(quán)限。
本文分析了流行的SQL注入方法及恢復(fù)手段。設(shè)計(jì)了一個(gè)簡(jiǎn)單有效的防御系統(tǒng),可對(duì)常見(jiàn)SQL注入進(jìn)行阻斷,其日志功能在記錄攻擊數(shù)據(jù)形式的同時(shí)為我們進(jìn)一步完善系統(tǒng)指出了方向。系統(tǒng)采用頁(yè)面調(diào)用形式,可移植性強(qiáng)、部署簡(jiǎn)單,并可自定義過(guò)濾參數(shù)。上海理工大學(xué)研究生部采用.NET+SQL Server開(kāi)發(fā)了多個(gè)信息應(yīng)用系統(tǒng),從Web站點(diǎn)到綜合教務(wù)管理系統(tǒng)在前期都不斷受到各種SQL注入攻擊的考驗(yàn)。在部署了本防御系統(tǒng)后,經(jīng)過(guò)長(zhǎng)期運(yùn)行,在各個(gè)應(yīng)用系統(tǒng)上都起到了很好的攔截效果,為保證信息系統(tǒng)的穩(wěn)定運(yùn)行提供了可靠的保障。☉
[1]張洪星,褚建立.基于ASP.NET的SQL注入攻擊及防范解決方案[J].電腦知識(shí)與技術(shù),2006(35).
[2]戴詩(shī)發(fā).校園網(wǎng)SQL注入攻擊與防范技術(shù)研究[J].昆明理工大學(xué)學(xué)報(bào),2005.Vol.30(3).
(編輯:隗爽)
book=11,ebook=16
TP309.2
A
1673-8454(2010)13-0011-03
*本文受上海市研究生教育創(chuàng)新計(jì)劃資助,項(xiàng)目編號(hào):SLCXPY1001。