文獻標識碼: A
文章編號: 0258-7998(2013)04-0137-04
SQL注入攻擊是一種常見的互聯(lián)網(wǎng)攻擊手段,它具有易操作、強隱蔽、高危害和難檢測等特點。由于SQL注入攻擊的對象是Web服務器后臺的數(shù)據(jù)庫,而數(shù)據(jù)庫往往存放重要的用戶數(shù)據(jù)或業(yè)務數(shù)據(jù),因而SQL注入攻擊的后果影響非常嚴重。特別對銀行、證券、電信、移動、政府以及電子商務企業(yè)等后臺數(shù)據(jù)庫。一旦遭受SQL注入而導致數(shù)據(jù)纂改或機密數(shù)據(jù)丟失,在經(jīng)濟角度和社會角度都將產(chǎn)生惡劣的影響。因此檢測和防范SQL注入是軟件安全領域的重要課題,具有極高的研究價值和意義。
常見的Web應用系統(tǒng)架構如圖1所示,其中包括Web服務器及后臺數(shù)據(jù)庫。在Web服務器上部署Web服務,用戶使用瀏覽器通過Http或Https協(xié)議與Web服務器進行交互。常稱之為B/S架構。
在該架構中,Web服務器向用戶提供各種應用服務,這些服務都涉及到與數(shù)據(jù)庫的交互,即伴執(zhí)行SQL語句。如果Web應用系統(tǒng)設計或實現(xiàn)不合理,將可能導致用戶對數(shù)據(jù)庫執(zhí)行的SQL語句偏離系統(tǒng)設計的預期,從而引發(fā)安全事故。
Java程序運行在JVM中,因為具有與平臺無關的特點,這種完全面向對象開發(fā)的語言廣泛應用在Web系統(tǒng)的設計中。針對Java源代碼的SQL注入攻擊檢測進行研究,對于提高Web應用系統(tǒng)的安全性具有重要意義。
本文介紹了SQL注入原理、目前的檢測方法以及Java代碼對數(shù)據(jù)庫操作的三種代碼結構。針對Java執(zhí)行SQL語句的特點,重點提出一種基于抽象語法樹進行SQL執(zhí)行路徑檢測的SQL注入檢測算法;在Web 應用程序發(fā)布前進行深入靜態(tài)分析和檢查,從而提高Web應用系統(tǒng)的安全性。算例分析和在實際Web系統(tǒng)中的應用結果表明,本文提出的SQL注入檢測算法具有高檢測率和低誤報率。
1 相關研究工作
SQL注入漏洞最早在2000年左右被提出,其后學者們對SQL注入的檢測和防護展開了一系列的研究。
典型的一種SQL注入例子如下:
(1)用戶登錄Web應用系統(tǒng)時,需要進行身份認證,主要輸入用戶名和密碼兩個變量v_usr和v_pwd;
(2)Web系統(tǒng)執(zhí)行合法性檢查的SQL語句為:“Select * from users where username=‘”+v_usr+“’and password=‘”+ v_pwd+“’”,如果用戶登錄時用戶取為‘admin’ or 1=1--,那么合法性檢查的SQL語句等效于Select * from users where username=‘ admin’ or 1=1;
顯然,用戶名取‘admin’ or 1=1--時,無論密碼輸入多少,都可以登錄系統(tǒng)。
SQL注入的檢測和防護方式目前主要有兩大類,一是系統(tǒng)上線前檢測,也稱為靜態(tài)檢測;二是系統(tǒng)在線運行防御,也稱為動態(tài)檢測。
動態(tài)檢測方式是一種黑盒檢測方法,對上線的系統(tǒng)進行SQL漏洞掃描,編制SQL注入攻擊腳本對Web系統(tǒng)進行試探,通過檢查Http的回應報文內容來判斷是否發(fā)生SQL注入攻擊,從而確定是否存在SQL注入漏洞。AppScan等工具可執(zhí)行此類安全檢測。
靜態(tài)檢測方法是一種白盒檢測方法[1],通過靜態(tài)語法解析查找Web 應用代碼中可能引發(fā)SQL注入的環(huán)節(jié),在Web應用發(fā)布前檢查代碼質量。Fotify等工具可執(zhí)行此類安全檢測。參考文獻[2-3]給出一種動態(tài)生成SQL語句進行類型正確性檢查的方法來檢測是否存在SQL注入,該方法的的缺點在于只能檢測句法結構或語句類型出現(xiàn)異常的SQL注入問題。參考文獻[4]提出一種自動推理機的方法對添加了輸入值后的SQL語句進行檢查,該方法的缺點在于只能檢測出重言式的SQL注入攻擊。此外,還有一些學者采用機器學習算法對SQL注入漏洞進行檢測[5],這一類檢測方法的檢測率和誤報率往往依賴于訓練集的大小。
2 Java源代碼靜態(tài)掃描分析思路
程序靜態(tài)分析指在不執(zhí)行程序的情況下,通過自動掃描代碼發(fā)現(xiàn)隱含的程序隱患[6],具備執(zhí)行速度快、效率高等優(yōu)點。對源代碼進行靜態(tài)分析時借鑒編譯技術的詞法分析和語法分析。源代碼進行靜態(tài)分析掃描原理如圖2所示。
Java程序與數(shù)據(jù)庫之間的交互主要通過Java數(shù)據(jù)庫連接JDBC進行。其數(shù)據(jù)庫操作涉及與數(shù)據(jù)庫建立連接、發(fā)送SQL指令、處理返回結果、斷開數(shù)據(jù)庫連接4個步驟。
具體實現(xiàn)上主要涉及的Java類有Connection類、DriverManager類、Statement類、ResultSet類、PreparedStatement類和callableStatement類。在代碼實現(xiàn)上往往有3種實現(xiàn)方式:
(1) 常規(guī)方式
//函數(shù) DB_SQL(SQL語句)
Connection con=DriverManager. getConnection(參數(shù)URL,參數(shù)用戶名,參數(shù)密碼);
Statement stat = con.createStatement();
ResultSet rs = stat.executeQuery("SQL語句");(或者executeUpdate /execute /executeBatch)
//此處為rs的處理代碼
rs.close(); stat.close(); con.close();
Java采用常規(guī)方式訪問數(shù)據(jù)庫,每次都需要進行建立連接,再執(zhí)行SQL語句,最后釋放連接。由于建立連接過程一般比較耗時(一般需要幾十毫秒至幾百毫秒之間),而且Statement對象每次執(zhí)行SQL語句的解析和編譯也比較耗時,如果涉及如下循環(huán)使用情況,則代碼的執(zhí)行效率將會比較低下。為此,對于需要頻繁建立數(shù)據(jù)庫連接的情況,可以采用連接池方式進行優(yōu)化;對于需要頻繁執(zhí)行相似SQL語句的情況,則可采用預編譯方式進行優(yōu)化。
while(N次)
{
DB_SQL(SQL語句);
}
(2) 預編譯方式
采用常規(guī)方式執(zhí)行SQL語句時,DBMS需要對SQL語句進行解析和編譯;而采用預編譯方式時,DBMS只在第一次對SQL語句進行解析和編譯。相比前者,后者更難注入SQL。原因在于,PreparedStatement對象執(zhí)行SQL語句前,需要設置“?”號對應的變量,例如ps.setInt(1,變量v1)、ps.setLong(2,變量v2) 表示SQL語句中第一個“?”號是int型、值為“變量v1”;這樣在安全性上相當于增加了一個類型匹配。
Connection con=DriverManager.getConnection(參數(shù)URL,參數(shù)用戶名,參數(shù)密碼);
while(N次)
{
PreparedStatement ps = con.prepareStatement(帶若干“?”號的SQL語句);
ps.setXX(“?”的序號, 變量); //XX包括int double等
ResultSet rs = ps.executeQuery();(或者executeUpdate /execute /executeBatch)
//此處為rs的處理代碼
rs.close();
}
ps.close(); con.close();
(3) 連接池方式
連接池(Connection Pool)是設計模式中資源池(Resource Pool)的一種具體應用,主要解決資源頻繁分配和釋放所帶來的性能問題。其基本思想是預先建立一個數(shù)據(jù)庫連接池,在該連接池中預先存放一定數(shù)量的連接,當需要建立數(shù)據(jù)庫連接時,并非新建一個數(shù)據(jù)庫連接,而是從連接池中取出一個連接對象,然后對該連接對象進行參數(shù)設置和使用,使用完畢后,并不釋放該連接,而是將連接對象的參數(shù)復位并回收。
采用連接池的應用開發(fā)方式與常規(guī)方式的代碼結構類似。區(qū)別是常規(guī)方式的連接對象在需要時才從堆中動態(tài)分配空間與數(shù)據(jù)庫建立連接,使用完畢后即斷開連接,等待Java的GC垃圾回收器發(fā)現(xiàn)該對象不再需要后,將回收連接對象的內存空間;而采用連接池方式,則是在連接池中預先建立一個若干數(shù)據(jù)的連接對象,需要使用時才從連接池中取出一個連接對象(不是臨時創(chuàng)建,因此效率高),使用完畢后,并不斷開連接,而是將該連接對象歸還給對象池。通過一個“借用”和“歸還”的方式使得可以高效地對付頻繁的數(shù)據(jù)庫訪問操作。目前常用的連接池主要有C3PO、BoneCP、DBCP、Proxool等。
綜上所述,無論采用哪一種數(shù)據(jù)庫操作方式,Java源代碼中可能出現(xiàn)SQL注入漏洞的代碼執(zhí)行過程中,一定經(jīng)過executeQuery、executeUpdate、execute 或executeBatch函數(shù)。本文提出的SQL檢測算法,正是通過定位這些函數(shù)并以此為分析SQL注入隱患的切入點,跟蹤這些函數(shù)的參數(shù)或參數(shù)表達式。如果這些參數(shù)表達式最終能追溯到某個特定的對象(如HttpServletRequest),則可以肯定這條路徑將可能存在SQL注入隱患。
3 Java源代碼SQL注入檢測算法
抽象語法樹AST(Abstract Syntax Tree)是程序源代碼的抽象語法結構的樹狀表現(xiàn)形式,樹上的每個節(jié)點表示源代碼中的一種結構,AST的好處在于不依賴于具體的方法和語言細節(jié)。對于源代碼的文法分析,首先進行詞法分析,將源代碼中所有字符串從前至后逐個字符進行掃描,并對每個“單詞”進行標識。這些“單詞”主要包括Java語言中的關鍵字、標識符、運算符和分隔符等。然后進行語法分析,將這些識別出來的“單詞”序列分解成各類Java語法單位。
根據(jù)源代碼靜態(tài)分析掃描原理,結合Java 1.6的文法定義,本文提出的SQL注入檢測算法通過對源代碼的詞法和語法分析,生成相應的抽象語法樹,定義規(guī)則,根據(jù)規(guī)則遍歷抽象語法樹。
本文提出的檢測算法實現(xiàn)步驟如下:
(1) 遍歷抽象語法樹,尋找METHOD_DECL結點中節(jié)點名為executeQuery或executeUpdate或execute或executeBatch的所有節(jié)點,并將它們保存在哈希表keyNode中。
(2) 找keyNode中的每一個節(jié)點,確認是否是正確的結點。首先得到keyNode節(jié)點的前繼表達式,并得到前繼表達式的返回值類型。若前繼表達式的返回值類型為Java.sql.Statement,則可確認此結點,并轉到下一步;若返回值類型不是Java.sql.Statement,則轉步驟(2),檢測下一個節(jié)點;
(3) 確認結點,取得第一個參數(shù)作為路徑結點,分析并跟蹤路徑結點的數(shù)據(jù)流。具體為:分析并跟蹤路徑結點表達式為變量表達式;分析并跟蹤路徑結點表達式為方法表達式;跟蹤退出的準則描述如下:①當所有跟蹤變量均到達常量定值,則此路徑不會產(chǎn)生SQL注入漏洞,轉步驟(2);②跟蹤到開始API定義的方法結點,轉步驟(4)。
(4) 記錄跟蹤到的SQL注入的侵入路徑,轉步驟(2),檢測下一個節(jié)點。若keyNode中所有結點都已檢測完成,則算法終止。
4 算法實驗
為了驗證本文提出的算法的有效性,以一個Java程序為實驗算例進行分析和說明,實驗算例代碼如圖3所示。
在實驗的Java源代碼中,可能產(chǎn)生SQL注入的開始API和結束API(即Java源代碼SQL注入檢測規(guī)則),具體如表1所示。
根據(jù)SQL注入檢測規(guī)則,利用本文所提出的檢測算法對圖3所示的Java源代碼進行掃描分析,產(chǎn)生的抽象語法樹如圖4所示,可發(fā)現(xiàn)SQL注入漏洞,并報告相應的路徑。
本文提出的SQL注入檢測算法已經(jīng)成功應用于本單位信息系統(tǒng)的Java源代碼靜態(tài)檢測中。在新上線運行的某Web系統(tǒng)(約10萬行代碼)靜態(tài)分析中,檢測時間僅為5 s,檢測準確識別率高達90%,而誤報率僅有10%;通過實驗和實際系統(tǒng)的測試和驗證,本文提出的Java源代碼SQL注入靜態(tài)分析算法具有很好的應用效果和前景。
參考文獻
[1] WILLIAM G J, VIEGAS H J, ORSO A. A classification of SQL injection attacks and countermeasures[C]. Proc. of International Symposium on Secure Software Engineering.2006.
[2] GOULD C, SU Z, DEVANBU P. JDBC checker: a static analysis tool for SQL/JDBC applications[C]. Proceeding of the 26th International conference on Software Engineering(ICSE). Washington D C: IEEE computer Society, 2004.
[3] GOULD C, SU Z, DEVANBU P. Static checking of dynamically generated queries in database applications[C].Proceedings of 26th International Conference on Software Engineering, 2004.
[4] WASSERMANN G, SU Z. An analysis framework for security in Web applications[C]. Proceedings of the FSE Work shop on Specification and Verification of Component Based System, 2004.
[5] HUANG Y W, HUANG S K, LIN T P, et al. Web application security assessment by fault injection and behavior monitoring[C]. Porceeding of the 11th International World Wide Conferecne, 2002.
[6] 張卓.SQL注入攻擊技術及防范措施研究[D].上海:上海交通大學,2007.