《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 通信與網(wǎng)絡(luò) > 設(shè)計(jì)應(yīng)用 > 基于靜態(tài)分析的Java源代碼SQL注入檢測(cè)算法
基于靜態(tài)分析的Java源代碼SQL注入檢測(cè)算法
來(lái)源:電子技術(shù)應(yīng)用2013年第4期
陳 豐, 余 蕓
南方電網(wǎng)公司信息部, 廣東 廣州510623
摘要: 研究了常見的SQL注入檢測(cè)和源代碼靜態(tài)分析掃描的原理,提出Java源代碼SQL注入檢測(cè)算法,該算法通過(guò)對(duì)Java源代碼詞法分析和語(yǔ)法分析、建立抽象語(yǔ)法樹、定義規(guī)則、遍歷語(yǔ)法樹和跟蹤等,檢測(cè)Java源代碼中可能的SQL注入路徑,測(cè)試結(jié)果表明,算法檢測(cè)效果良好,識(shí)別率高。
中圖分類號(hào): TP309.5
文獻(xiàn)標(biāo)識(shí)碼: A
文章編號(hào): 0258-7998(2013)04-0137-04
A Java source-code SQL injection attack detection algorithm based on static analysis
Chen Feng, Yu Yun
China Sourthern Power Grid Co., Ltd, Guangzhou 510623, China
Abstract: This paper researches the method of SQL injection attack detection and the principle of static analysis scanning, and presents a Java source-code SQL injection attack detection algorithm. The detection algorithm includes these steps: lexical analysis of source code, parsing of source code, constructing abstract syntax tree of source code, defining rules, abstract syntax tree traversal, tracking problems, detecting possible paths of SQL injection attack etc. Test results show that the proposed detection algorithm performs perfectly and has higher recognition rate.
Key words : static analysis; SQL injection attack; abstract syntax tree

    SQL注入攻擊是一種常見的互聯(lián)網(wǎng)攻擊手段,它具有易操作、強(qiáng)隱蔽、高危害和難檢測(cè)等特點(diǎn)。由于SQL注入攻擊的對(duì)象是Web服務(wù)器后臺(tái)的數(shù)據(jù)庫(kù),而數(shù)據(jù)庫(kù)往往存放重要的用戶數(shù)據(jù)或業(yè)務(wù)數(shù)據(jù),因而SQL注入攻擊的后果影響非常嚴(yán)重。特別對(duì)銀行、證券、電信、移動(dòng)、政府以及電子商務(wù)企業(yè)等后臺(tái)數(shù)據(jù)庫(kù)。一旦遭受SQL注入而導(dǎo)致數(shù)據(jù)纂改或機(jī)密數(shù)據(jù)丟失,在經(jīng)濟(jì)角度和社會(huì)角度都將產(chǎn)生惡劣的影響。因此檢測(cè)和防范SQL注入是軟件安全領(lǐng)域的重要課題,具有極高的研究?jī)r(jià)值和意義。

    常見的Web應(yīng)用系統(tǒng)架構(gòu)如圖1所示,其中包括Web服務(wù)器及后臺(tái)數(shù)據(jù)庫(kù)。在Web服務(wù)器上部署Web服務(wù),用戶使用瀏覽器通過(guò)Http或Https協(xié)議與Web服務(wù)器進(jìn)行交互。常稱之為B/S架構(gòu)。

    在該架構(gòu)中,Web服務(wù)器向用戶提供各種應(yīng)用服務(wù),這些服務(wù)都涉及到與數(shù)據(jù)庫(kù)的交互,即伴執(zhí)行SQL語(yǔ)句。如果Web應(yīng)用系統(tǒng)設(shè)計(jì)或?qū)崿F(xiàn)不合理,將可能導(dǎo)致用戶對(duì)數(shù)據(jù)庫(kù)執(zhí)行的SQL語(yǔ)句偏離系統(tǒng)設(shè)計(jì)的預(yù)期,從而引發(fā)安全事故。
    Java程序運(yùn)行在JVM中,因?yàn)榫哂信c平臺(tái)無(wú)關(guān)的特點(diǎn),這種完全面向?qū)ο箝_發(fā)的語(yǔ)言廣泛應(yīng)用在Web系統(tǒng)的設(shè)計(jì)中。針對(duì)Java源代碼的SQL注入攻擊檢測(cè)進(jìn)行研究,對(duì)于提高Web應(yīng)用系統(tǒng)的安全性具有重要意義。
    本文介紹了SQL注入原理、目前的檢測(cè)方法以及Java代碼對(duì)數(shù)據(jù)庫(kù)操作的三種代碼結(jié)構(gòu)。針對(duì)Java執(zhí)行SQL語(yǔ)句的特點(diǎn),重點(diǎn)提出一種基于抽象語(yǔ)法樹進(jìn)行SQL執(zhí)行路徑檢測(cè)的SQL注入檢測(cè)算法;在Web 應(yīng)用程序發(fā)布前進(jìn)行深入靜態(tài)分析和檢查,從而提高Web應(yīng)用系統(tǒng)的安全性。算例分析和在實(shí)際Web系統(tǒng)中的應(yīng)用結(jié)果表明,本文提出的SQL注入檢測(cè)算法具有高檢測(cè)率和低誤報(bào)率。
1 相關(guān)研究工作
    SQL注入漏洞最早在2000年左右被提出,其后學(xué)者們對(duì)SQL注入的檢測(cè)和防護(hù)展開了一系列的研究。
    典型的一種SQL注入例子如下:
    (1)用戶登錄Web應(yīng)用系統(tǒng)時(shí),需要進(jìn)行身份認(rèn)證,主要輸入用戶名和密碼兩個(gè)變量v_usr和v_pwd;
    (2)Web系統(tǒng)執(zhí)行合法性檢查的SQL語(yǔ)句為:“Select * from users where username=‘”+v_usr+“’and password=‘”+ v_pwd+“’”,如果用戶登錄時(shí)用戶取為‘admin’ or 1=1--,那么合法性檢查的SQL語(yǔ)句等效于Select * from users where username=‘ admin’ or 1=1;
    顯然,用戶名取‘admin’ or 1=1--時(shí),無(wú)論密碼輸入多少,都可以登錄系統(tǒng)。
    SQL注入的檢測(cè)和防護(hù)方式目前主要有兩大類,一是系統(tǒng)上線前檢測(cè),也稱為靜態(tài)檢測(cè);二是系統(tǒng)在線運(yùn)行防御,也稱為動(dòng)態(tài)檢測(cè)。
    動(dòng)態(tài)檢測(cè)方式是一種黑盒檢測(cè)方法,對(duì)上線的系統(tǒng)進(jìn)行SQL漏洞掃描,編制SQL注入攻擊腳本對(duì)Web系統(tǒng)進(jìn)行試探,通過(guò)檢查Http的回應(yīng)報(bào)文內(nèi)容來(lái)判斷是否發(fā)生SQL注入攻擊,從而確定是否存在SQL注入漏洞。AppScan等工具可執(zhí)行此類安全檢測(cè)。
    靜態(tài)檢測(cè)方法是一種白盒檢測(cè)方法[1],通過(guò)靜態(tài)語(yǔ)法解析查找Web 應(yīng)用代碼中可能引發(fā)SQL注入的環(huán)節(jié),在Web應(yīng)用發(fā)布前檢查代碼質(zhì)量。Fotify等工具可執(zhí)行此類安全檢測(cè)。參考文獻(xiàn)[2-3]給出一種動(dòng)態(tài)生成SQL語(yǔ)句進(jìn)行類型正確性檢查的方法來(lái)檢測(cè)是否存在SQL注入,該方法的的缺點(diǎn)在于只能檢測(cè)句法結(jié)構(gòu)或語(yǔ)句類型出現(xiàn)異常的SQL注入問(wèn)題。參考文獻(xiàn)[4]提出一種自動(dòng)推理機(jī)的方法對(duì)添加了輸入值后的SQL語(yǔ)句進(jìn)行檢查,該方法的缺點(diǎn)在于只能檢測(cè)出重言式的SQL注入攻擊。此外,還有一些學(xué)者采用機(jī)器學(xué)習(xí)算法對(duì)SQL注入漏洞進(jìn)行檢測(cè)[5],這一類檢測(cè)方法的檢測(cè)率和誤報(bào)率往往依賴于訓(xùn)練集的大小。
2 Java源代碼靜態(tài)掃描分析思路
    程序靜態(tài)分析指在不執(zhí)行程序的情況下,通過(guò)自動(dòng)掃描代碼發(fā)現(xiàn)隱含的程序隱患[6],具備執(zhí)行速度快、效率高等優(yōu)點(diǎn)。對(duì)源代碼進(jìn)行靜態(tài)分析時(shí)借鑒編譯技術(shù)的詞法分析和語(yǔ)法分析。源代碼進(jìn)行靜態(tài)分析掃描原理如圖2所示。

    Java程序與數(shù)據(jù)庫(kù)之間的交互主要通過(guò)Java數(shù)據(jù)庫(kù)連接JDBC進(jìn)行。其數(shù)據(jù)庫(kù)操作涉及與數(shù)據(jù)庫(kù)建立連接、發(fā)送SQL指令、處理返回結(jié)果、斷開數(shù)據(jù)庫(kù)連接4個(gè)步驟。
    具體實(shí)現(xiàn)上主要涉及的Java類有Connection類、DriverManager類、Statement類、ResultSet類、PreparedStatement類和callableStatement類。在代碼實(shí)現(xiàn)上往往有3種實(shí)現(xiàn)方式:
    (1) 常規(guī)方式
                                           //函數(shù) DB_SQL(SQL語(yǔ)句)
     Connection con=DriverManager. getConnection(參數(shù)URL,參數(shù)用戶名,參數(shù)密碼);
     Statement stat = con.createStatement();
     ResultSet rs = stat.executeQuery("SQL語(yǔ)句");(或者executeUpdate /execute /executeBatch)
                                             //此處為rs的處理代碼
    rs.close(); stat.close(); con.close();
    Java采用常規(guī)方式訪問(wèn)數(shù)據(jù)庫(kù),每次都需要進(jìn)行建立連接,再執(zhí)行SQL語(yǔ)句,最后釋放連接。由于建立連接過(guò)程一般比較耗時(shí)(一般需要幾十毫秒至幾百毫秒之間),而且Statement對(duì)象每次執(zhí)行SQL語(yǔ)句的解析和編譯也比較耗時(shí),如果涉及如下循環(huán)使用情況,則代碼的執(zhí)行效率將會(huì)比較低下。為此,對(duì)于需要頻繁建立數(shù)據(jù)庫(kù)連接的情況,可以采用連接池方式進(jìn)行優(yōu)化;對(duì)于需要頻繁執(zhí)行相似SQL語(yǔ)句的情況,則可采用預(yù)編譯方式進(jìn)行優(yōu)化。
    while(N次)
     {
      DB_SQL(SQL語(yǔ)句);
  }    
    (2) 預(yù)編譯方式
    采用常規(guī)方式執(zhí)行SQL語(yǔ)句時(shí),DBMS需要對(duì)SQL語(yǔ)句進(jìn)行解析和編譯;而采用預(yù)編譯方式時(shí),DBMS只在第一次對(duì)SQL語(yǔ)句進(jìn)行解析和編譯。相比前者,后者更難注入SQL。原因在于,PreparedStatement對(duì)象執(zhí)行SQL語(yǔ)句前,需要設(shè)置“?”號(hào)對(duì)應(yīng)的變量,例如ps.setInt(1,變量v1)、ps.setLong(2,變量v2) 表示SQL語(yǔ)句中第一個(gè)“?”號(hào)是int型、值為“變量v1”;這樣在安全性上相當(dāng)于增加了一個(gè)類型匹配。
     Connection con=DriverManager.getConnection(參數(shù)URL,參數(shù)用戶名,參數(shù)密碼);
     while(N次)
     {
      PreparedStatement ps = con.prepareStatement(帶若干“?”號(hào)的SQL語(yǔ)句);
     ps.setXX(“?”的序號(hào), 變量);   //XX包括int double等
    ResultSet rs = ps.executeQuery();(或者executeUpdate /execute /executeBatch)
                                  //此處為rs的處理代碼
      rs.close();
      }
     ps.close(); con.close();
    (3) 連接池方式
    連接池(Connection Pool)是設(shè)計(jì)模式中資源池(Resource Pool)的一種具體應(yīng)用,主要解決資源頻繁分配和釋放所帶來(lái)的性能問(wèn)題。其基本思想是預(yù)先建立一個(gè)數(shù)據(jù)庫(kù)連接池,在該連接池中預(yù)先存放一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫(kù)連接時(shí),并非新建一個(gè)數(shù)據(jù)庫(kù)連接,而是從連接池中取出一個(gè)連接對(duì)象,然后對(duì)該連接對(duì)象進(jìn)行參數(shù)設(shè)置和使用,使用完畢后,并不釋放該連接,而是將連接對(duì)象的參數(shù)復(fù)位并回收。
    采用連接池的應(yīng)用開發(fā)方式與常規(guī)方式的代碼結(jié)構(gòu)類似。區(qū)別是常規(guī)方式的連接對(duì)象在需要時(shí)才從堆中動(dòng)態(tài)分配空間與數(shù)據(jù)庫(kù)建立連接,使用完畢后即斷開連接,等待Java的GC垃圾回收器發(fā)現(xiàn)該對(duì)象不再需要后,將回收連接對(duì)象的內(nèi)存空間;而采用連接池方式,則是在連接池中預(yù)先建立一個(gè)若干數(shù)據(jù)的連接對(duì)象,需要使用時(shí)才從連接池中取出一個(gè)連接對(duì)象(不是臨時(shí)創(chuàng)建,因此效率高),使用完畢后,并不斷開連接,而是將該連接對(duì)象歸還給對(duì)象池。通過(guò)一個(gè)“借用”和“歸還”的方式使得可以高效地對(duì)付頻繁的數(shù)據(jù)庫(kù)訪問(wèn)操作。目前常用的連接池主要有C3PO、BoneCP、DBCP、Proxool等。
    綜上所述,無(wú)論采用哪一種數(shù)據(jù)庫(kù)操作方式,Java源代碼中可能出現(xiàn)SQL注入漏洞的代碼執(zhí)行過(guò)程中,一定經(jīng)過(guò)executeQuery、executeUpdate、execute 或executeBatch函數(shù)。本文提出的SQL檢測(cè)算法,正是通過(guò)定位這些函數(shù)并以此為分析SQL注入隱患的切入點(diǎn),跟蹤這些函數(shù)的參數(shù)或參數(shù)表達(dá)式。如果這些參數(shù)表達(dá)式最終能追溯到某個(gè)特定的對(duì)象(如HttpServletRequest),則可以肯定這條路徑將可能存在SQL注入隱患。
3 Java源代碼SQL注入檢測(cè)算法
    抽象語(yǔ)法樹AST(Abstract Syntax Tree)是程序源代碼的抽象語(yǔ)法結(jié)構(gòu)的樹狀表現(xiàn)形式,樹上的每個(gè)節(jié)點(diǎn)表示源代碼中的一種結(jié)構(gòu),AST的好處在于不依賴于具體的方法和語(yǔ)言細(xì)節(jié)。對(duì)于源代碼的文法分析,首先進(jìn)行詞法分析,將源代碼中所有字符串從前至后逐個(gè)字符進(jìn)行掃描,并對(duì)每個(gè)“單詞”進(jìn)行標(biāo)識(shí)。這些“單詞”主要包括Java語(yǔ)言中的關(guān)鍵字、標(biāo)識(shí)符、運(yùn)算符和分隔符等。然后進(jìn)行語(yǔ)法分析,將這些識(shí)別出來(lái)的“單詞”序列分解成各類Java語(yǔ)法單位。
    根據(jù)源代碼靜態(tài)分析掃描原理,結(jié)合Java 1.6的文法定義,本文提出的SQL注入檢測(cè)算法通過(guò)對(duì)源代碼的詞法和語(yǔ)法分析,生成相應(yīng)的抽象語(yǔ)法樹,定義規(guī)則,根據(jù)規(guī)則遍歷抽象語(yǔ)法樹。
    本文提出的檢測(cè)算法實(shí)現(xiàn)步驟如下:
    (1) 遍歷抽象語(yǔ)法樹,尋找METHOD_DECL結(jié)點(diǎn)中節(jié)點(diǎn)名為executeQuery或executeUpdate或execute或executeBatch的所有節(jié)點(diǎn),并將它們保存在哈希表keyNode中。
    (2) 找keyNode中的每一個(gè)節(jié)點(diǎn),確認(rèn)是否是正確的結(jié)點(diǎn)。首先得到keyNode節(jié)點(diǎn)的前繼表達(dá)式,并得到前繼表達(dá)式的返回值類型。若前繼表達(dá)式的返回值類型為Java.sql.Statement,則可確認(rèn)此結(jié)點(diǎn),并轉(zhuǎn)到下一步;若返回值類型不是Java.sql.Statement,則轉(zhuǎn)步驟(2),檢測(cè)下一個(gè)節(jié)點(diǎn);
    (3) 確認(rèn)結(jié)點(diǎn),取得第一個(gè)參數(shù)作為路徑結(jié)點(diǎn),分析并跟蹤路徑結(jié)點(diǎn)的數(shù)據(jù)流。具體為:分析并跟蹤路徑結(jié)點(diǎn)表達(dá)式為變量表達(dá)式;分析并跟蹤路徑結(jié)點(diǎn)表達(dá)式為方法表達(dá)式;跟蹤退出的準(zhǔn)則描述如下:①當(dāng)所有跟蹤變量均到達(dá)常量定值,則此路徑不會(huì)產(chǎn)生SQL注入漏洞,轉(zhuǎn)步驟(2);②跟蹤到開始API定義的方法結(jié)點(diǎn),轉(zhuǎn)步驟(4)。
    (4) 記錄跟蹤到的SQL注入的侵入路徑,轉(zhuǎn)步驟(2),檢測(cè)下一個(gè)節(jié)點(diǎn)。若keyNode中所有結(jié)點(diǎn)都已檢測(cè)完成,則算法終止。
4 算法實(shí)驗(yàn)
  為了驗(yàn)證本文提出的算法的有效性,以一個(gè)Java程序?yàn)閷?shí)驗(yàn)算例進(jìn)行分析和說(shuō)明,實(shí)驗(yàn)算例代碼如圖3所示。
    在實(shí)驗(yàn)的Java源代碼中,可能產(chǎn)生SQL注入的開始API和結(jié)束API(即Java源代碼SQL注入檢測(cè)規(guī)則),具體如表1所示。

    根據(jù)SQL注入檢測(cè)規(guī)則,利用本文所提出的檢測(cè)算法對(duì)圖3所示的Java源代碼進(jìn)行掃描分析,產(chǎn)生的抽象語(yǔ)法樹如圖4所示,可發(fā)現(xiàn)SQL注入漏洞,并報(bào)告相應(yīng)的路徑。

    本文提出的SQL注入檢測(cè)算法已經(jīng)成功應(yīng)用于本單位信息系統(tǒng)的Java源代碼靜態(tài)檢測(cè)中。在新上線運(yùn)行的某Web系統(tǒng)(約10萬(wàn)行代碼)靜態(tài)分析中,檢測(cè)時(shí)間僅為5 s,檢測(cè)準(zhǔn)確識(shí)別率高達(dá)90%,而誤報(bào)率僅有10%;通過(guò)實(shí)驗(yàn)和實(shí)際系統(tǒng)的測(cè)試和驗(yàn)證,本文提出的Java源代碼SQL注入靜態(tài)分析算法具有很好的應(yīng)用效果和前景。
參考文獻(xiàn)
[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注入攻擊技術(shù)及防范措施研究[D].上海:上海交通大學(xué),2007.

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。