《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 通信與網(wǎng)絡(luò) > 設(shè)計(jì)應(yīng)用 > 基于靜態(tài)分析的Java源代碼SQL注入檢測算法
基于靜態(tài)分析的Java源代碼SQL注入檢測算法
來源:電子技術(shù)應(yīng)用2013年第4期
陳 豐,, 余 蕓
南方電網(wǎng)公司信息部,, 廣東 廣州510623
摘要: 研究了常見的SQL注入檢測和源代碼靜態(tài)分析掃描的原理,提出Java源代碼SQL注入檢測算法,,該算法通過對Java源代碼詞法分析和語法分析,、建立抽象語法樹、定義規(guī)則,、遍歷語法樹和跟蹤等,,檢測Java源代碼中可能的SQL注入路徑,測試結(jié)果表明,,算法檢測效果良好,,識別率高。
中圖分類號: TP309.5
文獻(xiàn)標(biāo)識碼: A
文章編號: 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)隱蔽、高危害和難檢測等特點(diǎn),。由于SQL注入攻擊的對象是Web服務(wù)器后臺的數(shù)據(jù)庫,,而數(shù)據(jù)庫往往存放重要的用戶數(shù)據(jù)或業(yè)務(wù)數(shù)據(jù),因而SQL注入攻擊的后果影響非常嚴(yán)重,。特別對銀行,、證券、電信,、移動,、政府以及電子商務(wù)企業(yè)等后臺數(shù)據(jù)庫,。一旦遭受SQL注入而導(dǎo)致數(shù)據(jù)纂改或機(jī)密數(shù)據(jù)丟失,在經(jīng)濟(jì)角度和社會角度都將產(chǎn)生惡劣的影響,。因此檢測和防范SQL注入是軟件安全領(lǐng)域的重要課題,,具有極高的研究價值和意義。

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

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

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

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

    本文提出的SQL注入檢測算法已經(jīng)成功應(yīng)用于本單位信息系統(tǒng)的Java源代碼靜態(tài)檢測中,。在新上線運(yùn)行的某Web系統(tǒng)(約10萬行代碼)靜態(tài)分析中,檢測時間僅為5 s,,檢測準(zhǔn)確識別率高達(dá)90%,,而誤報率僅有10%;通過實(shí)驗(yàn)和實(shí)際系統(tǒng)的測試和驗(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)載,。