劉吉會,何成萬
(武漢工程大學 計算機科學與工程學院,武漢 430205)
互聯網服務的廣泛使用使Web 應用日漸復雜,Web 應用的安全問題也因其易用性和開放性而日益顯著,造成的漏洞越來越多[1-3]。在開放式Web 應用程序安全項目(Open Web Application Security Project,OWASP)發布的2013 年和2017年的Web 安全漏洞Top10[4]中,注入漏洞穩居第一,其中以SQL 注入為主體。SQL 注入攻擊是一種代碼注入攻擊[5-6]。Web 應用程序中的SQL 語句通常由程序中受信任的常量字符串和用戶輸入等不受信任的外部數據動態拼接在一起,這會導致不受信任的數據(例如用戶輸入)被數據庫引擎作為SQL 代碼片段執行[7]。攻擊者通過精心構造各種未經驗證的畸形外部輸入數據,欺騙數據庫服務器執行惡意構造的SQL 語句以達到攻擊的目的,對Web 應用潛在的數據庫安全構成嚴重的威脅。因此,對SQL 注入攻擊的檢測研究具有非常重要的意義。
現有的SQL 注入攻擊檢測主要采用基于SQL 語句合法性進行判別的方法來檢測攻擊[8]。根據檢測原理的不同,大致分為基于污點分析的方法、基于規則匹配的方法、基于文本向量化和機器學習的方法。基于文本向量化和機器學習的方法屬于新興的方法,由于數據集不夠、分類模型不完善、SQL 語句特征提取困難等問題,存在著諸多挑戰;而且在實際應用部署中,實現實時在線檢測比較困難。基于規則匹配的方法是傳統的SQL 注入攻擊檢測方法,又分為靜態檢測、動態檢測、動靜結合檢測。靜態檢測如JDBCChecker(Java DataBase Connectivity Checker)[9]就是在不運行程序的情況下通過源碼分析是否存在SQL 注入的可能。由于需要分析源代碼,無法發現運行時發生的部分攻擊,漏報率高且浪費人力物力,檢測效率低下。動態檢測如CANDID(dynamic CANDIDate evaluations)[10]在程序 運行時 動態挖 掘預期 的SQL 查詢結構與構造的SQL 語句結構比對,在無法獲得源代碼情況下通過程序運行時動態生成的模型來判斷是否存在SQL 注入攻擊。動靜結合檢測如AMNESIA(Analysis and Monitoring for NEutralizing SQL-Injection Attacks)[11]靜態分析應用程序生成正常SQL 語句查詢模型,然后在程序運行時進行動態監控,比較構造的SQL 語句是否符合靜態分析生成的SQL 語句模型,從而判斷是否存在SQL 注入攻擊并防御。基于規則匹配的方法在應用部署中要么需要源代碼,要么需要在程序運行前進行程序插樁修改原始程序行為,這類方法的可重用性不足,且不能在Web 應用開啟后加載檢測組件以達到在線檢測的目的。基于污點分析的方法大多需要修改應用程序的執行引擎,或需要修改應用的源代碼,或通過代碼重寫技術對Web 應用進行預編譯才能加載檢測組件。這些技術無法在應用運行時在線加載檢測組件,且與原始應用耦合性較高,容易干擾原始應用的業務邏輯,無法做到檢測組件的可重用性和在線檢測。
ECA(Event Condition Action)規則語言在Java 語義級別可以精確指定將要轉換的類及其中的方法以修改原始應用程序的行為或增加額外的功能。Byteman[12]是一個字節碼修改工具,采用這種清晰、簡單且易于使用的基于Java 的ECA規則語言,使得它在應用程序加載時或運行時更改應用程序的行為變得簡單。它工作時原始應用程序無須重寫和編譯。
本文提出一種基于ECA 規則和動態污點分析的在線檢測SQL 注入攻擊的模型。借助ECA 規則語言封裝動態污點分析的整個過程,在Web 應用運行時通過安裝ECA 規則腳本重新轉換構成應用程序和虛擬機程序的原始字節碼,從而在用戶提交請求時觸發相關檢測組件的執行,在線檢測是否存在SQL 注入攻擊。ECA 規則語言構成的檢測腳本完全獨立于Web 應用的業務邏輯,在Web 應用啟動后,整個檢測腳本將被轉化為內聯Java 代碼注入到Web 應用及其所屬的虛擬機中。實驗使用Byteman 實現了本文所提模型,并利用該模型在文獻[11]使用的Web 應用bookstore 和WebGoat[13]上做實驗,由ECA 規則語言封裝的檢測腳本經過安裝進這些應用的Byteman 代理讀取并自動轉換構成Web 應用和虛擬機的字節碼,從而將檢測代碼無縫插入到正在運行的應用基層子程序中。經過實驗驗證,這是一種低侵入性、輕量級的SQL 注入攻擊檢測方法,能夠在不修改應用程序執行引擎和源碼的前提下,實現Web 應用的在線檢測,且可以檢測出6種常見的SQL 注入攻擊類型。
Ray 等[5-6]定義了代碼注入攻擊。Halfond 等[14]對迄今為止已知的不同類型的SQL 注入攻擊進行了廣泛的回顧。SQL 注入攻擊檢測主要采用基于SQL 語句合法性判別的方法來檢測攻擊。依據檢測原理的不同,分為基于規則匹配的方法、基于污點的分析方法、基于文本向量化和機器學習的方法。
基于規則匹配的檢測方法通過創建特定的規則并對違反規則的行為進行識別來檢測攻擊。其中:正則表達式匹配的方法通過構建正則表達式對與所構建的正則表達式相違背的用戶輸入進行檢測過濾[15]。語法樹特征匹配的方法,如Bandhakavi 等[10]提出的方法,通過動態挖掘針對用戶任何輸入的、體現程序開發人員意圖的查詢結構,并將此結構與實際動態生成的SQL 查詢語句結構相比較以檢測是否發生SQL 注入攻 擊。與之類 似的是Halfond 等[11]提出的AMNESIA,在靜態分析階段,通過獲取正常查詢語句結構構建合法查詢的模型;在動態階段,監視SQL 語句的構建,并將構建的SQL 語句與靜態階段建立的合法查詢模型進行比較以檢測攻擊。文獻[16]的研究繼承了AMNESIA 的思想,借助靜態代碼工具獲取SQL 語句模型,利用面向方面編程(Aspect-Oriented Programming,AOP)技術捕獲程序執行中產生的SQL 語句,將靜態SQL 語句模型與產生的SQL 語句進行比較,判斷是否存在SQL 注入攻擊。文獻[17]中提出一種基于XML(eXtensible Markup Language)且只檢測重言式SQL 注入攻擊的方法。該方法包含一個XML 文件生成器,攔截用戶輸入并轉換成XML 格式;然后XML 文件將用戶憑據傳遞給Xschema 驗證器,將生成的用戶查詢與Xschema 文件中預定義的合法查詢進行比較,兩個查詢匹配時才允許其訪問,否則阻止訪問。該方法執行時間尚可,但檢測攻擊的類型單一。
基于污點分析的方案通過污點的標記和傳播,可以準確區分SQL 語句的可信部分和不可信部分。污點檢查比較可靠,主要分為靜態污點分析和動態污點分析。在靜態污點分析中:Jovanovic 等[18]提出的Pixy 使用流敏感、進程間和上下文敏感的靜態數據流分析方法來挖掘Web 應用程序漏洞;Livshits 等[19]使用靜態數據流分析技術檢測標記的用戶輸入是否到達SQL 語句執行點以挖掘SQL 注入漏洞;Wassermann等[20]將SQL 語句構造過程抽象為上下文無關文法,并使用靜態污點分析方法來判斷文法中的非終結符是否與用戶輸入有關。由于靜態污點分析不能很好地處理Web 應用語言的動態性,會引入較高的誤報率,再加上保守的程序分析,使誤報率會更高。
動態污點分析方法可以更好地處理程序的動態特性。Haldar 等[21]提出了一種動態解決方案,在運行時標記和跟蹤用戶輸入,并防止用戶不正當使用以惡意影響程序的執行;Perl 的污點模式[22]明確地將來自程序外部的數據標記為受污染,防止受污染的數據被用作某些敏感函數的參數;Nguyen-Tuong 等[23]修改PHP 執行引擎中String 類的數據結構和內置函數,在字符級對不可信數據進行污點標記與傳播,并在匯聚點處分析SQL 語句語法結構;Rafailidis 等[24]設計了污點傳播算法來實現實施安全策略的內聯監視器;Chin等[25]針對Java 實現了高效率的字符級別的污點傳播算法;董敏[26]基于C++語言的特性以影子內存原理封裝基本數據類型,擴展污點標記位,重載運算符以實現數據在程序運行時的實時傳播過程,并在污點匯聚點處解析SQL 語句的污點狀態以觸發報警裝置;Halfond 等[27]則提出了積極污點標記方法的新概念,污點標記可信數據,如程序中的硬編碼字符串,并動態跟蹤污點傳播軌跡,可有效解決不可信輸入來源廣泛、難以完整標記的問題。
從以上工作可以看出,對于SQL 注入攻擊檢測,動態污點追蹤機制提供額外的污點信息來判斷SQL 注入攻擊行為,提高了檢測準確性,且沒有復雜的靜態分析開銷。文獻[28-29]將此機制與AOP 的思想結合,使SQL 注入攻擊的安全關注點從應用邏輯中分離出來由方面封裝,賦予檢測模型更高的可重用性。從代碼級別捕獲Web 應用基礎設施的污點數據的流動,通過方面編織器將污點檢測代碼織入原始Web 應用相關的安全關注點中,在關注點中模擬動態污點分析的各個流程,避免了對Web 應用源碼及執行引擎的直接修改。他們的方法既實現了對多數SQL 注入攻擊類型的檢測,又對攻擊檢測代碼的可重用實現作出努力;但他們的方法部署需要預編譯加載檢測組件,在線加載檢測組件難以實現。
基于文本向量和機器學習的方法針對SQL 語句的合法性進行判斷。它們針對正常和惡意SQL 語句進行特征向量的提取和向量化,選取合適的分類模型進行數據集的訓練。由此研究人員提出了許多方法和改進的措施。如李紅靈等[30]提出的基于支持向量機(Support Vector Machine,SVM)和文本特征向量提取的SQL 注入攻擊檢測技術、蘇林萍等[31]提出的基于N-gram 和詞頻逆向文件頻率(Term Frequency Inverse Document Frequency,TF-IDF)的SQL 注入攻擊檢測方法等。相關數據集的數據量不夠、分類模型的不完善以及SQL 語句特征提取困難等問題,使這個方面的研究存在諸多困難;而模型檢測的準確度和效率完全取決于數據集的質量。
ECA 規則精確指定在運行時應如何改變應用程序行為。規則的三個組成部分事件(Event)、條件(Condition)、動作(Action)分別定義如下:1)在應用程序執行期間應該發生副作用的地方;2)副作用是否應該發生;3)副作用應該是什么。因此,ECA 規則可以識別應用程序中外部數據流動經過的函數,并在該函數執行過程中在規則指定的位置插入相應的副作用。如果條件判斷為真,副作用就會發生,就會改變原始應用的行為;反之,副作用不會發生。
污點分析技術[32]包括污點源、污點匯聚點和無害化處理等部分。其中,污點源表示將污點數據引入系統中;污點匯聚點表示系統將污點數據輸出到敏感數據區或外界,造成敏感數據區被改寫或機密數據被泄漏;無害化處理表示通過數據加密或重新賦值等操作使數據傳播不再對系統的完整性和機密性產生危害。污點分析就是分析程序中由污點源引入的數據能否不經無害化處理而直接傳播到污點匯聚點[33]。由于ECA 規則的特性,它可以精確識別污點源函數、污點傳播經過的函數和污點匯聚點函數,在這些函數對應位置中插入的副作用就是污點標記、污點傳播、污點檢查動作,而副作用發生的條件就是判斷函數參數及函數調用者對象是否攜帶污點,若攜帶污點,則執行相應的污點分析動作。
本文提出的基于ECA 規則和動態污點分析的SQL 注入攻擊檢測模型如圖1 所示。

圖1 基于ECA規則和動態污點分析的SQL注入攻擊檢測模型Fig.1 SQL injection attack detection model based on ECA rules and dynamic taint analysis
它的處理流程主要分為三個步驟:第一,針對污點源的ECA 規則自動識別污點源,在污點源處對被引入系統的外部數據進行污點標記;第二,針對污點傳播的ECA 規則自動識別污點傳播經過的函數,判斷函數參數以及函數調用者對象的污點狀態,以此決定是否標記函數返回值,從而在程序運行時實時跟蹤污點數據的流向;第三,針對污點匯聚點的ECA 規則自動識別污點匯聚點,在污點匯聚點處對將要執行的SQL 語句進行詞法語法分析評估其污點狀態,從而判斷是否存在SQL 注入攻擊。在Web 應用運行時,安裝ECA 規則,實現檢測模塊的自動在線加載。此時,檢測模塊就會在用戶提交請求后發揮作用。ECA 規則比較系統完整地模擬了動態污點分析過程,實現了針對待測Web 應用中外部數據進入系統后從污點源到污點匯聚點經過的所有可能的基本函數的自動識別以及在相應函數中插入相應的污點分析邏輯。這些基本函數包括服務器請求接口的方法(污點源,如ServeltRequest.getParameter())、字符串類中具有污點傳播能力的字符串操作方法(污點傳播經過的函數,如String.append())、Java 數據庫連接(Java Database Connectivity,JDBC)接口中的方法(污點匯聚點,如Statement.executeQuery())。在用戶發起請求后,Web 應用中與該請求相關的基本函數的執行就會觸發與之相關的ECA 規則的執行,相關規則就會隨著污點數據在系統中的流動而自動觸發執行污點標記、污點傳播、污點檢查動作,從而判斷當前用戶的請求是否存在SQL注入攻擊。當Web 應用處理用戶請求時,外部數據實際會經過哪些基本函數的處理對用戶而言是模糊的,對ECA 規則而言是透明的。檢測模塊獨立于原始Web 應用的業務邏輯,作為一個整體被ECA 規則定義,在線安裝ECA 規則可以將檢測模塊動態插入到正在運行的Web 應用中;同時,也可以在線卸載ECA 規則,被規則影響的基本函數就會恢復原狀。安裝卸載規則的過程中,無須重新編譯、打包、部署Web應用。
本文基于Java EE(Java platform,Enterprise Edition)框架作具體論述。不可信數據進入程序中,參與SQL 語句的動態構建,并最終被數據庫服務器當作SQL 代碼執行。由于SQL注入攻擊涉及的都是字符串的構建,因此本文為JDK(Java Development Kit)中的String、StringBuffer、StringBuilder 三個字符串類的實例建立一個映射。每一個字符串實例與一個StringData 類實例相對應,相對應的StringData 類實例存儲了該字符串實例的污點狀態信息。StringData 類包含一個布爾變量字段和一個布爾數組字段:布爾變量表征該實例是否被污染,布爾數組則表征該字符串實例的每個字符的污染狀況。若布爾變量為false,則相應的布爾數組為空,這樣可以節省內存。
動態污點標記如圖2 所示,在Web 應用運行時,污點源ECA 規則一經安裝,就會自動識別污點引入函數,在該函數業務邏輯中增加對規則的觸發調用。當用戶提交的數據經過污點引入函數時,污點標記規則自動觸發,評估條件為真執行污點標記動作,標記用戶提交的數據。

圖2 污點標記示意圖Fig.2 Schematic diagram of taint marking
污點標記的算法如算法1 所示,創建一個StringData 類,初始化該類字段,布爾變量字段賦為true,布爾數組字段的每一個數組元素賦值為true,然后以方法參數param為鍵將新創建的StringData 實例存儲到taintMaps 映射表中。這種標記的好處在于既不用擴展字符串類String 等的污點屬性,使污點標記的邏輯與原來字符串處理邏輯弱耦合,也不用在某些字符串處理函數再進行額外的污點標記和污點去除的操作,還可以保證污點標記的精度。
算法1 污點標記算法。
污點傳播算法的設計參考文獻[21,27-28]的思想。污點傳播分析要解決的就是外來數據在程序內部的實時傳播跟蹤與存儲的問題。ECA 規則負責識別污點傳播經過的函數,然后在規則動作執行條件中判斷經過函數的調用者和參數是否被污染:若被污染,在該字符串函數返回之前,規則將根據函數的調用者和參數的污點狀態將它們的污點狀態合并組合傳播給函數返回值;反之不執行相關的污點傳播動作。污點傳播邏輯由ECA 規則定義,而字符串處理函數的邏輯則在字符串操作類中,從而設計出既不會破壞程序執行邏輯,又能保持污點方法跟蹤污點數據的傳播軌跡的方法。
針對JDK 字符串類中的基礎字符串函數,本文逐一實現污點傳播邏輯。污點傳播算法如算法2所示,分三種情況進行討論:1)如果JDK 字符串類中函數(如toString()、subString()等)只有攜帶污點的字符串調用者對象,則將字符串調用者對象的污點狀態傳播給函數返回值;2)如果JDK 字符串類中函數(如構造函數)參數為攜帶污點的字符串對象,則將該字符串對象的污點狀態傳播給函數返回值;3)如果JDK 字符串類中函數是這一類函數(如append()、replace()等),則函數調用者對象和參數對象均可能攜帶污點,將這二者可能攜帶的污點狀態合并傳播給函數返回值。通過該算法實現JDK字符串類中基礎字符串函數級別的污點傳播分析,避免了傳統的基于指令級別的污點傳播分析。
算法2 污點傳播算法
由于字符串類為引用對象類型,字符串類之間賦值的本質是向某個內存的指針賦值。本文污點的存儲方式是基于映射的方式,即一個字符串對象對應一個污點存儲的位置,當帶污點的字符串對象賦值給另一個變量,則另一個變量與被賦值的變量指向同一個存儲污點的內存,賦值操作不用更新taintMaps 映射,即自動將污點從等號右邊傳向左邊。
標準Servlet 程序中所有和數據庫交互的相關操作都封裝在JDBC 庫中。SQL 注入污點匯聚點是消耗用戶輸入的敏感函數,如executeQuery()、executeUpdate()等。使用污點檢查規則就可以在函數開始執行前捕獲這些敏感函數的參數并對它們進行語法解析,從而判斷是否發生SQL 注入攻擊。若判斷發生SQL 注入攻擊,則污點檢查規則執行通知開發人員的動作。
對程序中動態構建的SQL 語句進行詞法語法分析以構建語法分析樹,遍歷語法分析樹的所有終端結點,檢查它們的污點狀態。若污點僅僅分布在字符串文本和數字文本中,則沒有發生SQL 注入攻擊;若污點部分或全部分布在SQL 關鍵字、操作符、特殊字符等,則可以認為發生SQL 注入攻擊[27]。為了降低污點傳播性能的損失,每次執行語法解析之前都會清空taintMaps 中存儲的鍵值對。污點檢查算法如算法3 所示。
算法3 污點檢查算法
本文基于Byteman 工具實現了所提出的模型。Byteman規則引擎負責解析ECA 規則,將它表示的內聯Java 代碼轉化為字節碼,由Byteman 代理插入到Web 應用的字節碼中。由此,在Web 應用請求數據流動的過程中,就會執行ECA 規則集指定的污點分析動作。ECA 規則語言涉及到的內置操作集由Byteman 的幫助類加以擴展或替換。由Byteman 幫助類實現有關動態污點分析動作的內置操作集,就可以使ECA規則語言具有污點分析的功能。基于Byteman 工具實現模型共分為四個部分:Byteman 幫助類的定義、污點標記實現、污點傳播實現以及污點檢查實現。
Byteman 單個ECA 規則的基本架構如圖3 所示。ECA 規則語言中,E(event)為規則事件,用來規范標識與目標類關聯的目標方法中的特定位置。目標方法可以是靜態或實例方法或構造函數。RULE、CLASS、METHOD、AT 子句定義規則事件。C為condition,由IF子句定義。A為actions,由DO 子句定義,當與規則匹配的類及方法執行時,就會觸發該規則的執行。由該規則轉化地注入應用程序中的字節碼執行過程是:首先判斷IF子句的condition表示的條件是否為真,若為真,則執行DO 子句后面的actions 表示的單個或多個動作;否則,不執行由DO 子句定義的動作,即規則雖然觸發但沒有執行實際的動作。Byteman 工具存在的意義在于為用戶提供ECA 規則語言,使用戶可以在Java 語義級別直觀地修改運行中的應用程序和JVM 的字節碼。Byteman 的底層規則引擎通過Java代理機制實現了ECA規則到字節碼的自動轉換。

圖3 單個ECA規則的基本架構Fig.3 Basic structure for single ECA rule
在圖3 中,HELPER 子句定義的是與該規則相關聯的、由用戶自行定義的幫助類。對于ECA 規則而言,可以使用的內置操作集并不固定。規則引擎將規則中調用的內置操作集與該規則相關聯的幫助類的公共實例方法相對應,任何被指定為幫助類的類必須是非抽象和可繼承的,它的公共實例方法自動變為規則事件、條件、動作中可調用的內置操作集。在圖4(a)~(c)的3 個規則中,setTaintedInSource、isTainted、setTaintedByMethod、parse 等內置操作對應下面自定義幫助類HelperSub2 的公共成員方法。所以規則condition 或actions 子句對某些方法的調用實質就是對該規則關聯的幫助類的公共實例方法的調用。在圖4 中,污點標記、污點傳播、污點檢查規則腳本都與幫助類HelperSub2 相關聯,由此有關污點標記、污點傳播、污點檢查和污點存儲的具體實現也是在該幫助類中完成的。該類編寫完成打包為jar 包,在Web 應用啟動后,使用Byteman 寫好的腳本bmsubmit 命令于命令行上在線提交該jar 包到引導類路徑中,以擴展在線提交規則集的內置操作集。根據圖4 所示的內容,下面將詳細闡述污點分析規則腳本的編寫以及相應的污點標記、傳播、檢查算法的實現。

圖4 Byteman幫助類的定義Fig.4 Definition of Byteman Helper class
以圖5 所示的污點規則示例1 進行描述,RULE 子句中RULE 關鍵字后面為規則名,INTERFACE、METHOD、AT 子句則表明該規則觸發執行的位置,即在所有實現javax.servlet.ServletRequest 接口的實現類中的getParameter 方法返回之前才觸發該規則的執行。IF 子句為規則動作是否執行的條件,DO 子句為該規則觸發后具體執行的操作,setTriggering(false)方法總是返回true,對getParameter 方法返回的字符串$!執行污點標記的動作,具體地設置污點標記的實現在Byteman 自定義幫助類HelperSub2 中完成。在該規則中,$!為Byteman 的特殊變量,自動與getParameter 方法的返回值綁定。

圖5 污點規則示例1Fig.5 Taint rule example 1
與圖5 類似的ECA 規則腳本共同監視應用可能引入外部數據的函數,一旦這些函數執行,就會執行相應的污點標記動作。這些腳本都與幫助類HelperSub2 相關聯,腳本調用的污點標記動作之一setTaintedInSource()在該幫助類中作一個公共成員方法來實現。核心代碼如下:
監控污點經過的字符串操作函數的規則集都與HelperSub2 類相關聯,從而將針對字符串操作函數的污點設置方法整合在一個類中。一系列監控污點傳播經過的函數的規則集和它們調用的在幫助類中實現的各污點傳播動作構成了本文所提模型中污點傳播算法的具體實現。
針對JDK 字符串類中每個字符串操作函數均有相應的規則需要編寫。以圖6 所示的規則示例2 舉例闡述,該規則匹配StringBuilder 類中的append(String)方法,判斷$!,$1的污點狀態以決定是否在該方法返回之前給該方法返回值設置污點標記。該規則中$1 與append 方法的第一個參數自動綁定。設置污點方法是setTaintedByAppend(),該方法針對append()方法進行處理,具體污點處理操作在自定義幫助類HelperSub2 中實現。由于利用Byteman 比較完整地實現了針對污點傳播經過的字符串函數的規則,但實際應用到哪些字符串函數對于用戶而言是模糊的,對于規則而言卻是透明的。由此,用戶不需要知道數據流經過哪些具體的字符串操作函數,由規則自動識別而觸發執行污點傳播動作。

圖6 污點規則示例2Fig.6 Taint rule example 2
針對圖 6 規則調 用的污 點傳播動作setTaintedByAppend ($!,$1),在幫助類HelperSub2 中實現的核心代碼如下:
判斷函數參數是否攜帶污點的內置操作isTainted()在幫助類HelperSub2 中實現的核心代碼如下:
圖7 規則示例3 顯示的規則識別所有實現Statement 接口的實現類的executeQuery()方法的執行,在該方法執行第一條語句前判斷規則條件以執行通知開發人員動作。在規則條件中,首先檢查該方法參數是否攜帶污點,若攜帶污點,則規則調用parse()方法對方法參數即動態構建的SQL 語句進行詞法語法分析,從而判斷是否存在SQL 注入攻擊。對于所有敏感函數接口(如executeUpdate 等),均有相應的規則與之對應,這些規則調用HelperSub2 類中的parse 方法,污點檢查算法在parse 方法中實現。

圖7 污點規則示例3Fig.7 Taint rule example 3
parse 方法實現的核心代碼如下:
為驗證本文所提模型的有效性,在文獻[11]中使用的bookstore 和WebGoat[13]上進行測試。為了在這些Web應用上進行測試,還需要針對每一個應用的SQL 注入攻擊測試集(負樣本)和正常訪問請求集(正樣本),負樣本中含有多種類型的SQL 注入攻擊,正樣本包含富文本字面量及無SQL 語義字符。在筆記本電腦上搭建實驗環境,利用正負樣本測試集測試目標應用以驗證SQL 注入攻擊在線檢測模型的有效性。
首先啟動Web 應用,此時在命令行輸入jps 查詢應用執行的進程號,并輸入Byteman 寫好的命令bminstall,將Byteman 代理安裝到對應進程(正在運行的Web 應用)的Java虛擬機中,使用bmsubmit 命令提交自定義幫助類jar 包,然后在線提交ECA 規則集。此時的Web 應用已經加載了在線檢測模塊,模塊隨時監測Web 應用接收的請求。在虛擬機Linux 系統中使用wget 命令批量提交請求以及手動注入,模擬攻擊者頻繁發送包含SQL 注入行為的請求和正常的請求,檢測模型會對每一個請求在應用中產生的SQL 語句進行評估以判斷是否存在SQL 注入攻擊行為。對檢測結果進行統計之后,結果如表1~3 所示。

表1 SQL注入測試用例及檢測結果Tab.1 SQL injection test cases and detection results
表1 列出了各種SQL 注入攻擊類型的測試用例代表的攻擊字符信息和檢測結果,所提模型能根據污染的敏感攻擊字符在SQL 語法分析樹中的位置判斷動態生成的SQL 語句的合法性,從而判斷出表1 中的測試用例存在SQL 注入攻擊行為。
表2 列出了針對每個Web 應用攻擊的SQL 注入攻擊請求樣本數和成功檢測到攻擊的樣本數。針對兩個Web 應用發送大約1 200 個SQL 注入攻擊請求樣本,發現本文模型可以檢測到絕大多數的攻擊樣本,說明該模型具有一定的檢測能力。

表2 惡意請求樣本檢測結果Tab.2 Detection results of malicious request samples
表3 給出了針對每個Web 應用發送的正常請求樣本數和檢測到SQL 注入攻擊行為的樣本數。從表中數據可以看出,發送了大約800 個正常請求樣本,本文檢測模型沒有檢測到SQL 注入攻擊行為,說明該模型并沒有將正常的請求誤認為存在SQL 注入攻擊行為的惡意請求,即不存在誤報的情況。

表3 正常請求樣本檢測結果Tab.3 Detection results of normal request samples
綜上所述,可以發現本文模型能夠檢測出常見SQL 注入攻擊類型,如重言式、非法或邏輯錯誤查詢、聯合查詢等,針對發送的SQL 注入攻擊請求樣本能識別出絕大多數具有SQL 注入攻擊行為的請求樣本,針對正常請求沒有出現誤報。上述實驗結果可以說明本文模型是有效的。
由于有些檢測方法源碼并不開放,難以復現,只能通過閱讀大量的文獻分別從檢測能力和部署要求等方面進行粗略的分析評估。每種檢測方法的檢測能力見表4,每種檢測方法的實施部署要求見表5。其中:表4 使用“√”表示可以檢測到此種類型的攻擊;“*”表示部分可以檢測的情況;“×”表示不能檢測該類型的攻擊。

表4 不同方法的檢測能力比較Tab.4 Comparison of detection capability of different methods

表5 不同方法的部署要求比較Tab.5 Comparison of deployment requirements for different methods
從表4 以看出,文獻[9]的方法側重于類型安全,文獻[17]的方法側重于重言式,它們只能檢測SQL 注入攻擊的一小部分,而當前其他一些主流方法基本都可以檢測到所有類型的SQL 注入攻擊,文獻[30-31]中通過機器學習與特征向量提取的方法構建檢測模型,模型訓練準確率分別可以達到91.05%、98.67%。本文方法檢測準確率達到99.42%,在檢測能力上可以與這些方法相當。
從表5 可以看出,文獻[10-11,27]的方法采用某種插樁工具離線插樁來加載檢測模塊,文獻[23]的方法修改了PHP解釋器,文獻[26]的方法則重新定義字符串類及其相關的賦值連接操作,用這種語言編寫有漏洞的Web 應用來加載檢測模塊。本文方法既不修改運行時系統,也不需要修改原始字符串類,在未作任何修改的Web 應用啟動后運行時就可以在線提交規則集以加載檢測模塊,部署方式更加靈活方便。
另外,本文和文獻[28]都采用代碼注入的方式將檢測代碼注入Web 應用程序實現SQL 注入攻擊檢測。文獻[28]的方法采用AOP 實現靜態注入,而本文使用ECA 規則實現了在線注入,可以實現Web 應用的在線檢測,并且ECA 規則可以在線卸載,使Web 應用恢復原狀。因此,本文模型是一個低侵入性的無須重新編譯、打包、部署應用的SQL 注入攻擊檢測模型。另外,文獻[28]的方法對不可信數據進行首尾標記,并把拼接后的字符串的屬性taint 設為true,而本文方法對不可信數據采用映射的方式進行污點標記與存儲,即每一個不可信數據對象與一個存儲污點信息的對象相對應,這樣標記的好處是不影響應用的字符串處理邏輯,與應用邏輯弱耦合,而且可以保證精度。
本文模型在加載后,除了可以檢測SQL 注入攻擊行為,還要考慮它對原始Web 應用造成的性能損失,即當用戶發起請求后,檢測模型能否及時給出檢測結果。在Web 應用的3個注入點,測試加載檢測模塊前、后提交正常和惡意請求后得到響應的時間,每個請求提交200 次,計算出平均響應時間。通過比較兩者時間的差異,初步評估模型施加給應用的性能開銷。測試結果如表6 所示。從表6 可以看出,3 個注入點測試中,當發送正常請求時,加載檢測組件后,平均響應時間最多增加11 ms;當發送惡意請求時,加載檢測組件后的平均響應時間最多增加13 ms。由此可以初步評估,本文模型加載后對Web 應用的施加的影響比較小,對正常和惡意的請求,模型能及時判斷出是否存在SQL 注入攻擊行為。

表6 注入點加載前后的平均響應時間比較 單位:msTab.6 Comparison of average response time before and after loading injection points unit:ms
針對當前SQL 注入攻擊檢測方法不能在線注入檢測代碼的不足,本文提出了一種基于ECA 規則和動態污點分析的SQL 注入攻擊檢測模型。該模型在Web 應用運行時安裝ECA 規則,自動加載SQL 注入攻擊檢測代碼。在攻擊者發送請求時自動觸發檢測組件的執行,從而在線檢測Web 應用是否受到SQL 注入攻擊。整個檢測模塊由ECA 規則腳本封裝在一起,與Web 應用原來的邏輯相互獨立,腳本可在線安裝和卸載,具有輕量級和低侵入性的部署優點,在腳本安裝卸載過程無須修改應用程序執行引擎和源碼,無須重新編譯、打包、部署Web 應用。本文基于Byteman 實現了所提模型,并通過實驗驗證了模型的有效性。但本文方法也具有局限性,只能解決污點傳播中數據依賴傳播,沒有考慮控制依賴傳播。因此未來的研究計劃中,將本文方法適用于其他種類的Web 安全威脅防御中。