潘秋紅,崔展齊,王林章,2,3+
1.南京大學 計算機科學與技術(shù)系,南京 210023
2.南京大學 計算機軟件新技術(shù)國家重點實驗室,南京 210023
3.江蘇省軟件新技術(shù)與產(chǎn)業(yè)化協(xié)同創(chuàng)新中心,南京 210023
4.北京信息科技大學 計算機學院,北京 100101
SQL(structured query language)注入是攻擊者由外部輸入向程序中原有的數(shù)據(jù)庫執(zhí)行語句中插入惡意SQL語句片段,篡改SQL執(zhí)行命令來操作數(shù)據(jù)庫的安全漏洞。無論是對于Web應用還是移動應用,SQL注入都是一個嚴重的安全問題。攻擊者可以利用SQL注入漏洞竊取用戶敏感信息,惡意篡改數(shù)據(jù)庫中的內(nèi)容,提升權(quán)限等,引發(fā)嚴重后果。根據(jù)OWASP(Open Web Application Security Project)發(fā)布的Web應用十大安全威脅中,從2010年至2017年4月,注入類漏洞都高居榜首[1]。
SQL注入漏洞對軟件安全產(chǎn)生了巨大威脅,對SQL注入的檢測和防范是開發(fā)者在開發(fā)軟件時必須考慮的一個重要因素。已經(jīng)提出了很多方法用于檢測Web應用中的SQL注入漏洞,主要可分為靜態(tài)分析[2]、動態(tài)測試[3]兩類。靜態(tài)分析方法如符號執(zhí)行技術(shù),其將符號作為值賦給變量,對程序的路徑進行模擬執(zhí)行,精確分析程序的代碼屬性[2]。動態(tài)測試則要通過運行軟件來得到程序的動態(tài)行為信息,包括分析軟件的覆蓋率、監(jiān)控內(nèi)存的狀態(tài)、分析執(zhí)行軌跡、提取程序不變式等[3]。同時,針對Web應用中的SQL注入漏洞已有很多工具得到了廣泛應用,如HPFortify SCA[4]、Coverity[5]等。
近年來,隨著無線通信技術(shù)和移動互聯(lián)網(wǎng)迅猛發(fā)展,移動終端普及率快速提高。據(jù)CNNIC(China Internet Network Information Center)第39次《中國互聯(lián)網(wǎng)絡發(fā)展狀況統(tǒng)計報告》[6],截至2016年12月,我國手機網(wǎng)民規(guī)模已達到6.95億,臺式電腦、筆記本的上網(wǎng)比例則持續(xù)下降,網(wǎng)民上網(wǎng)設備進一步向移動端集中。其中,據(jù)CNNIC《2015年中國手機網(wǎng)民網(wǎng)絡安全狀況報告》[7],使用Android操作系統(tǒng)的手機占67.4%。根據(jù)Veracode 2016年發(fā)布的軟件安全狀態(tài)報告,在Android應用存在的安全漏洞中,SQL注入漏洞位列第八[8]。然而,Coverity、FindBugs[9]等面向Web應用的通用軟件質(zhì)量及安全漏洞檢測工具未關(guān)注移動應用的SQL注入特性,導致無法有效識別Android應用中的SQL注入漏洞。此外,用于檢測SQL注入漏洞的方法未使用污點分析等技術(shù),針對Android應用進行靜態(tài)污點分析的工具,如Flow-Droid[10]等,不支持直接檢測SQL注入漏洞,即使通過人工修改配置文件增加對SQL注入漏洞的描述,也只是分析SQL方法中的SQL參數(shù)是否被污染,沒有考慮應用中是否對外部輸入進行過合法性檢查,導致誤報率較高。
針對上述問題,本文提出了一種基于污點分析的Android應用SQL注入漏洞靜態(tài)檢測方法。首先,根據(jù)Android應用的字節(jié)碼文件進行程序靜態(tài)分析,并在其上定位SQL注入漏洞的SQL方法和SQL參數(shù);然后,通過靜態(tài)污點分析方法,檢測SQL參數(shù)是否來自外部輸入;最后,基于SQL注入的輸入驗證機制,通過識別應用中是否存在對污染的SQL參數(shù)進行過合法性檢查,來判斷是否存在SQL注入漏洞。
本文的貢獻包括以下兩點:
(1)針對Android應用,提出一種基于污點分析的SQL注入漏洞靜態(tài)檢測方法;
(2)基于所提出的方法實現(xiàn)了原型工具SQLInj,并設計了一組實驗來驗證所提出方法的有效性。
本文組織結(jié)構(gòu)如下:第2章介紹SQL注入漏洞模型;第3章詳細分析基于靜態(tài)分析的Android應用SQL方法及參數(shù)定位;第4章介紹方法的原型工具實現(xiàn)和實驗評估;第5章討論與本文相關(guān)的研究工作;第6節(jié)總結(jié)了本文的工作,并對下一步的研究計劃進行展望。
SQL注入漏洞是發(fā)生在使用數(shù)據(jù)庫對數(shù)據(jù)進行管理的應用程序中的一種安全漏洞,其本質(zhì)是攻擊者通過表單等方式進行外部輸入,在應用程序中預先定義好的數(shù)據(jù)庫查詢語句中插入惡意的SQL語句,篡改其含義來欺騙數(shù)據(jù)庫服務器執(zhí)行非授權(quán)的查詢[11],通過這些操作獲得數(shù)據(jù)庫信息,非法讀取、修改、添加、刪除數(shù)據(jù),私自添加賬號,注入木馬等其他病毒。
攻擊者一般通過構(gòu)造有特殊含義的SQL語句進行SQL注入攻擊,攻擊方式大致可以分為以下幾類[12-13]:重言式與注釋符攻擊、非法/邏輯錯誤查詢攻擊、聯(lián)合查詢攻擊、推斷攻擊、基于存儲過程或函數(shù)攻擊、復合查詢攻擊、編碼替換攻擊等。
對于每種SQL注入攻擊方式,其注入的字符串中通常會包含不同的敏感字符,這些字符是SQL語言中定義的擁有特殊含義的字符,攻擊者就是通過這些字符篡改原SQL指令。將各類SQL注入攻擊方式可能采用的敏感字符進行了整理,如表1所示。

Table 1 SQL injection sensitive characters表1 SQL注入敏感字符
為了能夠檢測出Android應用中的SQL注入漏洞,首先需要對SQL注入漏洞進行建模和分析,然后在此基礎上對程序進行靜態(tài)分析,并在代碼中定位SQL注入攻擊的SQL方法和SQL參數(shù),最后通過污點分析及判斷合法性檢查判定程序中是否存在SQL注入漏洞。
假設將由若干語句(statement)組成的Android應用程序(program)表示為P={s1,s2,…,sn},則可將SQL注入漏洞模型定義如下:
(1)SQL方法為語句集合SSQL?P中的元素,其中,對任意的語句si∈SSQL,si為SQL操作語句,SQL操作語句包括rawQuery、execSQL、query等與數(shù)據(jù)庫訪問相關(guān)的API調(diào)用。
(2)對于SQL方法si,變量集合Pari={pari,1,pari,2,…,pari,m}為si所使用的參數(shù),其中,pari,j∈Pari即為si的SQL參數(shù)。
(3)對于任意的SQL參數(shù)pari,j∈Pari若其與P的外部輸入相關(guān),且在使用前未進行過合法性檢查,則認為SQL方法si存在SQL注入漏洞。
以圖1所示的代碼片段為例,其功能為當USER表中存在用戶輸入的用戶名且其密碼也正確時允許其登錄。首先,分析程序發(fā)現(xiàn)第5行為SQL方法android.database.sqlite.SQLiteDatabase.rawQuery;然后,分析該SQL方法rawQuery中的SQL參數(shù)為sql和null;最后,對SQL參數(shù)進行分析,其中,參數(shù)sql在第3行通過字符串username和password拼接而來,而username和password是應用登錄界面用戶輸入的用戶名和密碼,因此SQl參數(shù)sql與外部輸入有關(guān),且在SQL方法rawQuery執(zhí)行前,程序并沒有對SQL參數(shù)sql進行合法性檢查,因此,可以判斷SQL方法raw-Query處存在SQL注入漏洞。若攻擊者在用戶名和密碼處均輸入“1’OR‘1’=‘1”,則會通過SQL方法rawQuery中的SQL參數(shù)sql,將外部輸入傳遞到后臺數(shù)據(jù)庫中。此時執(zhí)行的SQL查詢語句的形式為:
SELECT*from USER WHERE USERNAME=‘1’OR‘1’=‘1’AND PASSWORD=‘1’OR‘1’=‘1’;
在這種情況下,該SQL查詢語句的結(jié)果恒為真,將會成功利用SQL注入漏洞進行攻擊,攻擊者無需正確的用戶名和密碼即可直接登錄。

Fig.1 Example of SQL injection圖1 SQL注入示例
針對缺少專用的Android應用SQL注入漏洞檢測工具,而現(xiàn)有的通用檢測工具用于檢測Android應用SQL注入漏洞時精確度較低的問題,本文提出了一種靜態(tài)檢測Android應用中潛在SQL注入漏洞的方法。如圖2所示,首先,通過靜態(tài)分析處理程序的結(jié)構(gòu),獲得程序的控制流圖和數(shù)據(jù)流圖,并在程序中定位SQL方法和SQL參數(shù);然后,對程序進行靜態(tài)污點分析,判斷SQL方法中的參數(shù)是否來自外部輸入;最后,對于使用了污點數(shù)據(jù)的SQL方法,要判斷應用中是否對其中的SQL參數(shù)進行了合法性檢查,若不存在合法性檢查,則認為這一條SQL方法存在SQL注入漏洞。

Fig.2 Flowchart of static detection approach for SQL injection vulnerability inAndroid applications圖2 Android應用中SQL注入漏洞靜態(tài)檢測方法流程圖
為了能夠?qū)Υa進行靜態(tài)檢測,需要對程序的結(jié)構(gòu)進行靜態(tài)分析,使用合適的數(shù)據(jù)結(jié)構(gòu)來描述代碼。為擴大方法的適用范圍,靜態(tài)分析的對象采用了Android應用的字節(jié)碼文件而非源代碼。首先對程序進行靜態(tài)分析,通過控制流分析、數(shù)據(jù)流分析等技術(shù)剖析程序的結(jié)構(gòu);然后在程序中定位SQL注入漏洞模型中的SQL方法及相應SQL參數(shù)。圖3為通過靜態(tài)分析定位Android應用SQL注入相關(guān)SQL方法及SQL參數(shù)的流程圖。對于應用的class文件以及依賴的jar文件,首先需要對字節(jié)碼進行控制流分析。控制流表示程序的單個語句、指令或者函數(shù)調(diào)用的順序,通過有向圖表示控制流,形成控制流圖。控制流圖表示了程序執(zhí)行過程中所有可能遍歷的路徑,它的每個結(jié)點是一個基本塊,有向邊指明了基本塊間的執(zhí)行關(guān)系。控制流只能從基本塊中的第一個指令進入該塊,除了基本塊的最后一個指令,控制流在離開基本塊之前不會停機或者跳轉(zhuǎn)[14]。確定了基本塊之后,就可以根據(jù)條件或無條件轉(zhuǎn)移指令來識別基本塊間的前后流通關(guān)系,以此建立字節(jié)碼文件的控制流圖。

Fig.3 Process of locating SQL method and parameter based on static analysis圖3 基于靜態(tài)分析的SQL方法及參數(shù)定位流程
有了控制流圖之后,可以對程序進行進一步的數(shù)據(jù)流分析。數(shù)據(jù)流分析是一種用于獲取程序中數(shù)據(jù)是如何沿著程序執(zhí)行路徑進行流動的信息的技術(shù)。在數(shù)據(jù)流分析中,通過對一組約束求解,就可以得到每個點上的數(shù)據(jù)流值,可分為基于語句語義約束和基于控制流約束。本文采用的是基于控制流約束方法,即在基本塊之內(nèi)時,每條語句輸出的數(shù)據(jù)流就是下一條語句輸入的數(shù)據(jù)流。在基本塊之間時,每條控制流邊都對應著新的約束,通過反復計算使系統(tǒng)達到穩(wěn)定。
根據(jù)定義的SQL注入漏洞模型,遍歷所有方法的控制流圖,關(guān)注其中用于方法調(diào)用的指令,定位使用SQL方法的位置信息。對SQL方法的參數(shù)進行數(shù)據(jù)流分析,定位每個SQL參數(shù)的位置、參數(shù)標識等信息。可以定位程序中調(diào)用的所有SQL方法,以及每個SQL方法對應的SQL參數(shù)信息。定位SQL方法和SQL參數(shù)后,調(diào)用靜態(tài)污點分析功能,分析對應的SQL參數(shù)是否來自外部輸入。對于使用了外部輸入作為參數(shù)的SQL方法,需要進一步驗證程序中是否針對其SQL參數(shù)進行過合法性檢查。
本文提出的靜態(tài)檢測SQL注入漏洞方法的核心就是對程序進行靜態(tài)污點分析。本文使用的程序靜態(tài)分析部分是基于FindBugs使用的BCEL框架,可對應用的字節(jié)碼進行處理。靜態(tài)污點分析通常可分為過程內(nèi)污點傳播和過程間污點傳播兩類。考慮到部分應用會使用特定的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù),如數(shù)組、Map等,增加了特殊數(shù)據(jù)結(jié)構(gòu)污點傳播。下面將分別對3種靜態(tài)污點傳播規(guī)則進行介紹。
3.2.1 特殊數(shù)據(jù)結(jié)構(gòu)污點傳播規(guī)則
對于外部輸入的數(shù)據(jù),很多程序都是選擇直接通過字符串進行存儲和修改。但是,除此之外,有時會使用特定的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù),如數(shù)組、Map等。下面分別為數(shù)組結(jié)構(gòu)、實現(xiàn)Collection接口和Map接口的類中的污點傳播規(guī)則。
(1)數(shù)組結(jié)構(gòu)
對于數(shù)組結(jié)構(gòu),可以將其視為一個整體進行處理。如果將一個污點數(shù)據(jù)傳遞給數(shù)組的一個元素,那么就將整個數(shù)組都標記為污染,而不是只將該索引位置標記。然后,對污染數(shù)組的所有讀寫操作都會將污染傳播。
如圖4中所示的代碼片段,字符串taintStr為污染數(shù)據(jù),在第3行將其賦值給數(shù)組spreadArray的第2個元素時,將整個spreadArray標記為污點數(shù)據(jù)。然后在第4行將spreadArray的第一個元素賦值給字符串str時,雖然之前并沒有將污點數(shù)據(jù)賦值給spreadArray[0],但是整個spreadArray數(shù)組空間都被標記為污染了,因此str也會被標記為污點數(shù)據(jù)。

Fig.4 Array taint propagation圖4 數(shù)組污點傳播
(2)Collection接口和Map接口
Java語言中定義了Collection和Map作為所有集合和Map類的接口,開發(fā)者可以通過實現(xiàn)這些接口的子類來更加方便地組織復雜的數(shù)據(jù),如List、Hash-Set、TreeMap等。因此,本文方法也要對這些結(jié)構(gòu)體進行污點傳播處理。這些結(jié)構(gòu)體的污點傳播規(guī)則與數(shù)組類型相似,也是將結(jié)構(gòu)體當作一個整體進行污點標記,即只要將一個污染數(shù)據(jù)傳遞給結(jié)構(gòu)體,就將整個結(jié)構(gòu)體視為污染。然后對于點運算符“.”,取最左邊對象的污染信息,如a.b.c的污染信息即為a的污染信息。
3.2.2 過程內(nèi)污點傳播規(guī)則
過程內(nèi)污點傳播是以方法為單位進行的。圖5為過程內(nèi)污點分析的流程,對于每個方法,需要一個污點數(shù)據(jù)集實時記錄方法中的污點信息。先初始化污點數(shù)據(jù)集,并將參數(shù)污點信息和與外部輸入有關(guān)的方法、變量加入污點數(shù)據(jù)集。然后遍歷程序,根據(jù)指令類型進行相應的操作:對于變量讀取指令,記錄變量的污點信息;對于普通賦值指令,若之前讀取了污點數(shù)據(jù),則該指令把污點數(shù)據(jù)賦值給當前變量,并將該變量加入污點數(shù)據(jù)集;對于特殊結(jié)構(gòu)體讀寫指令,進行特殊數(shù)據(jù)結(jié)構(gòu)污點傳播;對于方法調(diào)用指令,若該指令調(diào)用子方法,則進行過程間污點傳播,若其對結(jié)構(gòu)體進行操作,則進行特殊數(shù)據(jù)結(jié)構(gòu)污點傳播,若其是預先定義好的配置文件中的方法,表示其會把污點標記從參數(shù)傳播到方法返回值,則將返回值加入污點數(shù)據(jù)集;對于方法返回指令,其是方法中最后一條指令,在記錄方法的參數(shù)和返回值的污點信息后,輸出整個污點數(shù)據(jù)集。其算法描述如算法1。
算法1過程內(nèi)污點傳播算法
輸入:CFGcfg,F(xiàn)ileconfig//污染源配置文件JavaClassjavaclass//字節(jié)碼文件
輸出:HashSetTaintSet//方法污點數(shù)據(jù)集


3.2.3 過程間污點傳播規(guī)則
本文采用的過程間污點傳播規(guī)則為:對于進行了過程內(nèi)污點傳播的方法,傳播結(jié)束時會記錄此方法的參數(shù)和返回值污點信息。因此,首先分析被調(diào)用方法參數(shù),若是之前掃描過該方法,且參數(shù)污點信息相同,則直接獲取掃描時返回值的污點信息;否則,將參數(shù)的污點信息傳遞給被調(diào)用方法,對其進行過程內(nèi)污點傳播,然后將其返回值的污點信息返回給調(diào)用該方法的位置。其算法描述如算法2所示。
算法2過程間污點傳播算法
輸入:Methodcall//源方法
Methodcalled//子方法
HashMapAnalysisedMap<StringpamInfo,StringresultInfo>//記錄進行過程內(nèi)污點分析的方法的參數(shù)和返回值污點信息,pamInfo為方法調(diào)用時參數(shù)污點信息,resultInfo為方法返回值污點信息
輸出:Stringresultinfo//子方法返回值污點信息
1.獲取子方法called參數(shù)污點信息paminfo

Fig.5 In-process taint propagation圖5 過程內(nèi)污點傳播

對于使用了來自外部輸入?yún)?shù)的數(shù)據(jù)庫執(zhí)行方法,還無法確定其中確實存在SQL注入漏洞。若應用中對數(shù)據(jù)庫查詢語句的參數(shù)進行過合法性檢查,就可以避免出現(xiàn)SQL注入的問題。因此,在進行污點分析以后,還要判斷應用中是否對使用了污點數(shù)據(jù)的SQL方法中的SQL參數(shù)進行過合法性檢查。常見的合法性檢查的方法有以下幾種:
(1)參數(shù)化方法。很多數(shù)據(jù)庫都提供了參數(shù)化的方法,使用這些方法執(zhí)行SQL語句時,數(shù)據(jù)庫服務器先是對SQL指令進行編譯,然后再將參數(shù)代入,而不是將參數(shù)也當成語句的一部分。因此,即使參數(shù)中存在惡意片段,也不會被數(shù)據(jù)庫執(zhí)行。比如Android應用中可以使用compileStatement方法,將其中外部輸入都用“?”代替,然后通過相應的bind方法對參數(shù)進行配置,這樣就不會存在SQL注入問題。
(2)白名單驗證。若開發(fā)者已經(jīng)知道某些形式的參數(shù)不會導致SQL注入漏洞,則可以在執(zhí)行數(shù)據(jù)庫操作前將參數(shù)與這些安全的形式進行驗證。比如通過Pattern.matcher與事先定義好的模式進行匹配,或者通過String提供的方法判斷參數(shù)中是否存在敏感字符等。而本文在掃描前兩層基本塊中,若是執(zhí)行到調(diào)用了白名單驗證使用的方法,且其參數(shù)為正在檢測的數(shù)據(jù)庫執(zhí)行語句的污點數(shù)據(jù)參數(shù),就認為程序中對這條SQL方法進行過合法性檢查。
(3)過濾、轉(zhuǎn)義敏感字符。實現(xiàn)過濾或轉(zhuǎn)義敏感字符的一個常用方法就是使用replace之類的方法對表1中的敏感字符進行操作,如圖6中第6行使用的Matcher.replaceAll方法。當掃描的前兩個基本塊中包含對敏感字符的過濾或者轉(zhuǎn)義處理,也能認為應用中進行了合法性檢查。
如算法3所示,本文只考慮使用了污染數(shù)據(jù)的SQL方法所在基本塊及前兩層的所有基本塊,掃描這些基本塊中是否對指定的SQL參數(shù)進行過合法性檢查。如圖6中的代碼片段,第10行中的SQL方法rawQuery位于基本塊B4中,且其參數(shù)sql為污點數(shù)據(jù)。則先檢查B4在執(zhí)行該方法前是否對sql進行過合法性檢查,若沒進行過就依次掃描上一層基本塊B3、B2,若上一層仍未進行合法性檢查,就再依次掃描兩層前的基本塊,該示例中僅有基本塊B1。最終,若SQL方法所在基本塊及前兩層基本塊都未進行過合法性檢查,則可以認為這個使用了污點數(shù)據(jù)的SQL方法存在SQL注入漏洞。在這個示例中,位于基本塊B3的第6行代碼進行了合法性檢查,則第10行的數(shù)據(jù)庫執(zhí)行方法是安全的。

Fig.6 Examples of legitimate check圖6 合法性檢查示例
算法3合法性檢查判斷
輸入:Fileconfig//合法性檢查相關(guān)方法配置文件
Stringpam//SQL方法中使用的污染參數(shù)
CFGcfg,Methodmethod,Locationloc
輸出:Boolean//是否進行過合法性檢查

在Java代碼靜態(tài)分析工具FindBugs的基礎上,本文實現(xiàn)了基于污點分析的Android應用SQL注入漏洞靜態(tài)檢測原型工具SQLInj。SQLInj首先靜態(tài)分析Android應用的字節(jié)碼文件,在程序中定位SQL注入漏洞的SQL方法和SQL參數(shù),然后通過靜態(tài)污點分析技術(shù)檢測SQL語句中的污點數(shù)據(jù),最后判斷程序是否對SQL方法中使用的污點數(shù)據(jù)進行過合法性檢查來報告是否存在SQL注入漏洞。如圖7所示,SQLInj的總體框架主要分為程序靜態(tài)分析、污點分析及合法性檢查3個模塊。
4.1.1 程序靜態(tài)分析
FindBugs中實現(xiàn)了對字節(jié)碼的控制流分析,在控制流圖基礎上,能得到每條指令的數(shù)據(jù)流信息。FindBugs中提供了很多種數(shù)據(jù)流信息,如當前指令所活躍的數(shù)據(jù)是否為常量、空值等,本文使用ConstantDataflow和ValueNumberDataflow來判斷參數(shù)是否為常量字符串及其名稱,并對FindBugs中提供的ValueNumberDataflow相關(guān)方法進行了修改,使得在進行ValueNumber數(shù)據(jù)流分析后,能同時獲取局部變量和全局變量的名稱。
4.1.2 靜態(tài)污點分析
靜態(tài)污點分析需要兩個配置文件:source.config和derivation.config。其中,source.config文件中記錄了與污染源有關(guān)的方法,在靜態(tài)污點分析中,根據(jù)其配置污染源并初始化污點數(shù)據(jù)集。derivation.config文件中是能夠?qū)⑽埸c標記從污染數(shù)據(jù)傳播給新數(shù)據(jù)的方法。首先,按照配置文件識別污染數(shù)據(jù);然后,根據(jù)污點傳播規(guī)則將所有被外部輸入影響的方法和變量進行標記;最后,判斷當前的SQL方法是否使用了被污染的參數(shù)。
4.1.3 合法性檢查
在配置文件legimacy.config中定義了3.3節(jié)中所介紹的合法性檢查相關(guān)的方法。根據(jù)合法性檢查判斷規(guī)則,如果使用了污點數(shù)據(jù)的SQL方法所在的基本塊以及前兩層的基本塊中使用過legimacy.config文件中定義的方法,即認為程序中對這條SQL方法進行過合法性檢查。

Fig.7 General framework of SQLInj圖7 SQLInj總體框架
4.1.4 檢測結(jié)果報告
當掃描完程序所有字節(jié)碼文件后,SQLInj會輸出最終的SQL注入漏洞檢測結(jié)果,報告所有SQL注入漏洞的SQL方法所在的類、方法、在源文件中的具體行數(shù),以及具體是哪一個數(shù)據(jù)庫執(zhí)行方法等信息。圖8為檢測結(jié)果報告中的一條錯誤信息示例,從中能夠看到該SQL注入漏洞發(fā)生在MainActivity類的SQLInjectTest方法中,漏洞產(chǎn)生的原因是在此方法中將一個污染數(shù)據(jù)傳遞給SQL方法android.database.sqlite.SQLiteDatabase.rawQuery,該SQL方法位于源代碼MainActivity.java的第118行。

Fig.8 Example of SQLInj detection result圖8 SQLInj檢測結(jié)果示例
使用SQLInj檢測只需要Android應用的APK文件,但由于需要確認誤報情況,因此實驗選擇了SQLInject、sieve等6個確定存在SQL注入漏洞的開源Android應用進行實驗。如表2所示,6個實驗對象的規(guī)模從500行到20 000行不等,表2中的第3列給出了應用功能的簡要描述。
為評估本文所使用方法在檢測SQL注入漏洞上的有效性,擴展了FindBugs原有的SQL漏洞注入檢測功能,在不改變其檢測機制的基礎上,使其能夠支持檢測Android應用SQL注入漏洞。將FindBugs運行的結(jié)果與SQLInj的結(jié)果進行對比,可以驗證使用污點分析及合法性檢查判斷對檢測結(jié)果精度的影響。
表3是SQLInj對6個應用的檢測結(jié)果,其中已知漏洞為每個應用中已知存在SQL注入漏洞的SQL方法數(shù)量,污染方法是進行靜態(tài)污點分析發(fā)現(xiàn)使用了污點數(shù)據(jù)的SQL方法的數(shù)量,疑似漏洞數(shù)是通過合法性檢查判斷后,存在SQL注入漏洞的SQL方法數(shù)量。然后,通過對每個應用中檢測出的疑似漏洞進行判斷,分析此處是否真實存在SQL注入漏洞。經(jīng)分析確實存在的SQL注入漏洞為確認漏洞,未被檢測到的SQL注入漏洞為漏報漏洞。表中第6列和第7列為SQLInj的漏報情況。實驗結(jié)果表明,SQLInj在6個Android應用中共檢測出35個SQL注入漏洞。對檢測出的SQL注入漏洞進行檢查發(fā)現(xiàn),對其中4個應用的分析未出現(xiàn)漏報,2個應用的分析存在漏報,平均漏報率為9.1%。對產(chǎn)生漏報的原因進行分析發(fā)現(xiàn),在進行污點分析時,為了提高分析效率,采取了記錄執(zhí)行過的過程內(nèi)污點分析方法的參數(shù)及返回值等污點信息,當再次調(diào)用同一方法時,不再進行過程內(nèi)污點分析,直接采用之前的污點分析信息。這一措施導致若某方法使用的全局變量在首次調(diào)用時與外部輸入無關(guān),但在之后的調(diào)用中與外部輸入相關(guān)時,會產(chǎn)生漏報。實驗結(jié)果表明,本文所使用的方法能有效檢測出Android應用中的90%以上的SQL注入漏洞,漏報率較低。而FindBugs通過檢測SQL方法的參數(shù)是否為常量字符串來判斷此處是否存在SQL注入漏洞,因此基本不會發(fā)生漏報的現(xiàn)象,但精確度較低。

Table 2 Description of experimental objects表2 實驗對象說明

Table 3 Detection results of SQLInj表3 SQLInj檢測結(jié)果
SQLInj與FindBugs的誤報情況對比如表4所示。使用FindBugs分析的誤報率最低為33.3%,最高的達到85.1%,平均誤報率為62.5%。使用SQLInj的誤報率最低為0,最高為25.0%,平均誤報率為7.5%。這是因為只要數(shù)據(jù)庫執(zhí)行方法的參數(shù)為諸如方法返回值、外部傳參、字符串拼接等,F(xiàn)indBugs就會認為存在SQL注入漏洞,而SQLInj只有當SQL方法的參數(shù)與外部輸入有關(guān)且未進行合法性檢查時才認為存在SQL注入漏洞。SQLInj存在誤報的原因是SQLInj不能檢測出應用在SQL方法前兩層基本塊之前進行的敏感字符過濾等合法性檢查,誤報存在SQL注入漏洞。實驗結(jié)果表明,本文所使用的基于污點分析的SQL注入漏洞靜態(tài)檢測方法有效降低了誤報率。

Table 4 Comparison of false positive表4 誤報情況對比
此外,還使用了綜合評價指標來評價SQLInj和FindBugs檢測結(jié)果的綜合性能。將檢測結(jié)果的確認漏洞稱為TP,表示檢測存在SQL注入漏洞且確實存在SQL注入漏洞的SQL方法數(shù)量。將疑似漏洞與確實漏洞的差稱為FP,表示檢測存在SQL注入漏洞,但其實是安全的SQL方法數(shù)量。將已知漏洞與確實漏洞的差稱為FN,表示沒有檢測出但實際存在SQL注入漏洞的SQL方法數(shù)量。準確率P=TP/(TP+FP),表示被正確檢測出的SQL方法中確實存在SQL注入漏洞的比例;召回率R=TP/(TP+FN),表示所有確實存在SQL注入漏洞的SQL方法中被正確檢測出來的比例;綜合評價指標F值F=2PR/(P+R),表示準確率和召回率的加權(quán)調(diào)和平均,綜合了準確率和召回率的結(jié)果,有利于對檢測結(jié)果綜合性能的評價[15]。
SQLInj與FindBugs的綜合評價標準F值對比結(jié)果如表5所示。FindBugs的F值最低為0.27,最高為0.80,平均值為0.53。SQLInj的F值最低為0.78,最高為1.00,平均值為0.91,比FindBugs高了約38%。因此,本文所使用的基于污點分析的SQL注入漏洞靜態(tài)檢測方法的綜合性能更好。

Table 5 Comprehensive contrast between FindBugs and SQLInj表5 FindBugs與SQLInj綜合對比情況
本文提出的方法能夠有效地檢測出Android應用中存在的SQL注入漏洞,并降低了誤報率。但是該方法的效果仍受到以下方面限制:
(1)實驗數(shù)據(jù)集的代表性。為了驗證SQLInj檢測結(jié)果的正確性,選擇使用開源的Android應用進行實驗,況且樣本數(shù)量也還不夠,需要提高實驗數(shù)據(jù)集的代表性。
(2)本文方法仍存在漏報問題。主要原因為FindBugs按照調(diào)用樹自底向上掃描方法所在class文件中的所有方法,這導致個別方法在被調(diào)用前就已經(jīng)被掃描過了,當此方法被調(diào)用時若其所在類的全局變量曾被改變,將使得此方法返回值污染信息發(fā)生變化,但如果此方法參數(shù)的污點信息與第一次掃描時相同,不會再重新掃描,可能會產(chǎn)生漏報。此外,合法性檢查不夠精確也可能會導致漏報。通過掃描SQL方法前兩層基本塊中是否進行了合法性檢查來判斷是否存在SQL注入,若程序中進行了合法性檢查,但檢查條件并不準確,可能會導致檢查后SQL參數(shù)中仍存在會導致SQL注入的字符串,從而引起漏報。
(3)本文方法仍存在誤報問題。只掃描SQL方法前兩層基本塊中是否進行了合法性檢查,當程序中合法性檢查的位置與SQL方法距離較遠時,可能會產(chǎn)生誤報。
由于SQL注入漏洞的風險性以及普遍性,如何檢測SQL注入漏洞的問題引起了很多國內(nèi)外學者的關(guān)注,目前已經(jīng)做出了大量的研究工作,主要分為靜態(tài)分析和動態(tài)測試兩大類。另外,因為本文方法主要基于污點分析技術(shù),所以對使用污點分析的相關(guān)工作也進行了總結(jié)。
程序靜態(tài)分析是不需要程序?qū)嶋H運行,而是在編譯時就獲得程序的相關(guān)屬性,在此基礎上對程序進行分析的技術(shù)。文獻[16]對近幾年使用靜態(tài)檢測SQL注入的方法進行了分析。符號執(zhí)行技術(shù)是靜態(tài)分析的一種,用來決定是哪些輸入導致程序每個片段執(zhí)行的分析方法。當使用符號執(zhí)行來分析程序時,程序?qū)⒎栕鳛橹蒂x給變量,對程序的路徑進行模擬執(zhí)行,精確分析程序的代碼屬性[2,17]。文獻[18-19]使用靜態(tài)方法檢測Web應用中的SQL注入漏洞,文獻[20-22]則是通過靜態(tài)方法針對Android應用進行檢測。
除此之外,Coverity[5]和FindBugs[9]是使用較多的靜態(tài)軟件質(zhì)量及安全漏洞檢測工具。其中,Coverity使用過程間靜態(tài)分析、字節(jié)精度分析、虛假路徑剪枝等技術(shù)對軟件源碼進行靜態(tài)分析,并提供了完整的路徑覆蓋,確保每一行代碼以及潛在的執(zhí)行路徑都能被測試;FindBugs則是對應用的字節(jié)碼文件進行數(shù)據(jù)流分析,并與漏洞缺陷模式進行匹配。但是,兩者的SQL注入漏洞檢測功能主要是針對Web應用的,無法對Android應用進行檢測。
動態(tài)分析技術(shù)是將程序在真實或虛擬機上運行,并對運行過程進行分析的方法。在靜態(tài)分析中,有很多情況被認為是可能發(fā)生的,但在動態(tài)分析中,其分析的路徑都是動態(tài)執(zhí)行,確實發(fā)生了的,并且可以觀察到程序運行時的狀態(tài)。Chess和West在2008年提出了一種檢測漏洞的動態(tài)分析方法[23]。在SQL注入問題上,也有很多方法是使用動態(tài)分析技術(shù)檢測的,如文獻[24-26]是動態(tài)檢測Web應用中的SQL注入漏洞,文獻[27]則將動態(tài)技術(shù)應用到檢測Android應用上的SQL注入。
污點分析可以分為靜態(tài)和動態(tài)污點分析兩種。文獻[28-29]使用靜態(tài)污點分析技術(shù)檢測Android應用中的安全漏洞,文獻[30]則提出一種在Java虛擬機中的動態(tài)污點分析方法,并結(jié)合了靜態(tài)分析方法來收集可到達的方法,以減少運行時開銷。在Android應用污點分析中,F(xiàn)lowDroid[10]和TaintDroid[31]是兩個具有代表性的工具。FlowDroid是一款針對Android應用的上下文、流、字段、對象敏感和生存周期感知的靜態(tài)污點分析工具,但其不支持SQL注入漏洞的檢測。TaintDroid則是通過動態(tài)污點分析跟蹤信息流的流動,但只會顯示數(shù)據(jù)流動信息,而不會對漏洞進行檢測。
本文針對Android應用中的SQL注入漏洞,提出一種基于污點分析的SQL注入漏洞靜態(tài)檢測方法。該方法首先對應用進行靜態(tài)分析,在程序中定位SQL注入漏洞的SQL方法和SQL參數(shù);然后通過靜態(tài)污點分析方法檢測SQL方法是否使用了污點數(shù)據(jù);最后識別應用中是否存在對污點數(shù)據(jù)進行過合法性檢查。基于上述方法,實現(xiàn)了原型工具SQLInj,并對存在SQL注入漏洞的Android應用進行了實驗。
在本文研究的基礎上,計劃進一步研究如何通過JPF-Android等工具自動產(chǎn)生SQL注入攻擊,以驗證SQL注入漏洞的存在,并在檢測出SQL注入后,嘗試在源碼中進行漏洞修復。