肖添明 管劍波 蹇松雷 任 怡 張建鋒 李 寶
(國防科技大學計算機學院 長沙 410073)
軟件脆弱性是指軟件在開發(fā)、部署、執(zhí)行整個過程中存在的缺陷,不法分子可利用這些缺陷繞過系統(tǒng)的訪問控制、非法竊取較高的權限等,這可能造成用戶隱私數(shù)據(jù)泄露、數(shù)字資產被盜、系統(tǒng)信息被更改等安全問題,從而導致企業(yè)和個人巨大的經濟損失和名譽損失.隨著現(xiàn)在軟件系統(tǒng)的復雜度越來越高,規(guī)模越來越大,脆弱性代碼出現(xiàn)的頻率也在不斷提升.根據(jù)美國國家漏洞數(shù)據(jù)庫(National Vulnerability Database, NVD)[1]公布數(shù)據(jù)顯示,2018年公布的脆弱性代碼數(shù)目為16 511個,2019年公布的脆弱性代碼數(shù)目為17 305個,2020年公布的脆弱性代碼數(shù)目為18 352個.從數(shù)據(jù)中可以看出,脆弱性代碼出現(xiàn)的次數(shù)一直在不斷上升,因此及時發(fā)現(xiàn)軟件中存在的脆弱性代碼是一份十分重要的工作.
目前檢測軟件脆弱性的方法主要有靜態(tài)、動態(tài)和混合3大類.靜態(tài)方法主要是通過分析軟件源代碼來檢測脆弱性,并不運行軟件,對運行環(huán)境的要求較低,檢測的普適性更強.傳統(tǒng)的靜態(tài)方法包括基于規(guī)則的分析[2]、代碼相似性檢測[3](即代碼克隆檢測)和符號執(zhí)行[4]等方法.其中,基于規(guī)則的分析主要依靠專家人工去發(fā)現(xiàn)脆弱性代碼的規(guī)則,并對源代碼進行規(guī)則匹配來檢測脆弱性;代碼相似性檢測是將源代碼與脆弱性代碼進行相似度比較,進而檢測脆弱性;符號執(zhí)行是將輸入用符號來表征而不是具體值,將程序的執(zhí)行過程和程序變量表征成符號表達式來發(fā)現(xiàn)脆弱性.傳統(tǒng)的靜態(tài)檢測方法不能檢測未知的脆弱性且誤報率往往比較高[5].與靜態(tài)方法不同,動態(tài)方法是通過實際運行軟件來尋找脆弱性,因此可以發(fā)現(xiàn)軟件運行時的錯誤.動態(tài)方法包括模糊測試[6]和污點分析[7]等方法.模糊測試主要是通過向目標系統(tǒng)提供非預期的輸入并監(jiān)視異常結果來發(fā)現(xiàn)軟件脆弱性的方法;污點分析主要是通過實時監(jiān)控程序的污點數(shù)據(jù)在系統(tǒng)程序中的傳播來檢測數(shù)據(jù)能否從污點源傳播到污點匯聚點,進而檢測軟件中的脆弱性.動態(tài)測試方法檢測準確率高,但通常十分耗時并且缺乏完整性,容易出現(xiàn)漏報的現(xiàn)象.混合方法結合了靜態(tài)和動態(tài)分析技術,與靜態(tài)方法相比降低了誤報率,與動態(tài)方法相比減少了運行負載,但混合方法難以全部實現(xiàn)自動化檢測,并且對未知脆弱性的檢測效果相對較弱.
目前,軟件規(guī)模越來越龐大和復雜,脆弱性形式也更趨向多樣化,傳統(tǒng)的軟件脆弱性檢測方法在處理復雜且多樣化的脆弱性方面存在困難.與傳統(tǒng)的軟件脆弱性檢測方法相比,基于機器學習的方法可以從海量數(shù)據(jù)中發(fā)現(xiàn)和學習規(guī)律,具有可自動尋找脆弱性的特點,減少了人工參與度,提高了檢測的自動化程度.基于機器學習的軟件脆弱性檢測方法能通過學習已有的脆弱性代碼特征檢測出類似或未知脆弱性.與基于規(guī)則的分析方法相比,無需人工進行規(guī)則的提取,降低了人的主觀性對于誤報率和漏報率的影響等優(yōu)勢;機器學習算法具有自動學習脆弱性代碼的特點,與代碼相似性分析方法相比,在檢測未知脆弱性方面有一定優(yōu)勢;與符號執(zhí)行相比,無需分析程序的執(zhí)行過程以構建執(zhí)行路徑,可檢測的脆弱性類型更具有一般性;與動態(tài)方法相比,無需運行軟件,只需分析軟件源代碼,降低了對運行環(huán)境的配置要求.因此,機器學習方法和工具被逐漸應用于軟件脆弱性檢測領域,代碼表征方式和脆弱性特征提取是該領域的重要關注點.
基于機器學習的軟件脆弱性檢測方法通常分為4步:1)數(shù)據(jù)預處理.對數(shù)據(jù)集進行切分、標記等預處理操作.2)代碼表征.利用抽象語法樹或者代碼度量等信息對源代碼進行表示,并利用詞向量模型將源代碼的表示信息轉換成數(shù)值型向量.3)特征提取.利用神經網絡模型學習代碼的向量表征,獲取代碼的高級表示.4)脆弱性檢測.利用機器學習算法學習代碼的高級表示,并以進行脆弱性檢測.通過以上4步就可以利用機器學習的方法來進行脆弱性檢測.由于單一軟件中的軟件脆弱性較少,而機器學習模型需要大量的數(shù)據(jù)來進行訓練,因此可用于機器學習模型訓練的真實數(shù)據(jù)集一般由多個軟件的源代碼混合而成.目前,現(xiàn)有方法已實現(xiàn)在多個軟件源代碼混合的真實數(shù)據(jù)集上做軟件脆弱性檢測,但其誤報率和漏報率較高[8].研究發(fā)現(xiàn),現(xiàn)有方法在代碼表征過程中存在著語法和語義信息的損失[8].
機器學習算法能夠有效學習到脆弱性代碼的特征是提高脆弱性檢測效果的重要因素之一,而在學習特征的過程中學習模型的輸入數(shù)據(jù)比學習模型的選擇更為重要[9].因此,為了提高特征提取模型和脆弱性檢測模型輸入數(shù)據(jù)的質量,本文在代碼表征和特征提取2個階段展開研究.本文提出了一種基于代碼屬性圖(code property graph, CPG)和Bi-GRU(bi-directional gated recurrent unit)的軟件脆弱性智能檢測方法,主要改進有2個方面:改進代碼的表征方式,降低代碼表征過程中的信息損失,提高了表征能力;優(yōu)化特征提取模型,提高了模型的脆弱性特征提取能力.本方法首先采用開源靜態(tài)分析工具Joern[10]從源代碼中提取出代碼屬性圖,再從代碼屬性圖中提取出抽象語法樹序列、控制流圖序列,然后利用Bi-GRU從序列中提取出脆弱性代碼的特征,最后使用隨機森林模型構建脆弱性檢測器進行脆弱性檢測.經實驗驗證,該方法可有效提高面向多個軟件源代碼混合的真實數(shù)據(jù)集的脆弱性檢測效果,降低誤報率和漏報率.本文的主要貢獻包括3個方面:
1) 提出了一種基于代碼屬性圖的軟件脆弱性智能檢測方法(vulnerability detection based on code property graph, VDCPG),該方法基于代碼屬性圖對源代碼進行表征,并根據(jù)在LibTIFF數(shù)據(jù)集上的實驗結果選擇基于Bi-GRU的特征提取模型對表征向量進行特征提取,降低了不同項目編碼風格差異對脆弱性檢測效果的影響.實驗結果表明,該方法可有效提高面向多個軟件源代碼混合的真實數(shù)據(jù)集的脆弱性檢測效果,與Lin等人[8]的方法相比,該方法的精確率和召回率最大提高了35%和22%.
2) 針對現(xiàn)有方法在代碼表征能力不足的問題,提出了一種基于代碼屬性圖的表征方式,利用從函數(shù)的代碼屬性圖中提取的抽象語法樹序列和控制流圖序列對函數(shù)進行表征,以減少代碼表征過程中的語法和語義信息的損失,提高表征能力.在本文實驗中,與其他表征方式相比,基于代碼屬性圖的表征方式最大可提高30%的精確率和18%的召回率.
3) 在特征提取階段,基于Bi-GRU和Bi-LSTM(bi-directional long short-term memory)構建多個提取模型.通過實驗發(fā)現(xiàn),與基于Bi-LSTM構建的特征提取模型相比,利用Bi-GRU構建的特征提取模型最大可提高10%的精確率和6%的召回率.因此本方法選擇利用Bi-GRU構建特征提取模型來挖掘脆弱性代碼的特征,提高特征提取模型的脆弱性特征提取能力,進而改善了面向多個軟件源代碼混合的真實數(shù)據(jù)集的脆弱性檢測效果.
隨著人工智能的發(fā)展,基于數(shù)據(jù)驅動的機器學習算法由于其智能化、可自動學習脆弱性代碼特征的特點,被研究者們應用到軟件脆弱性檢測領域,覆蓋了靜態(tài)分析、動態(tài)分析以及動靜態(tài)分析結合等典型場景.面向動態(tài)分析場景的研究主要針對緩解模糊測試、符號執(zhí)行等動態(tài)分析方法存在的程序路徑覆蓋率低、路徑爆炸以及約束求解難等問題,將機器學習方法用于測試輸入生成與篩選、路徑約束求解以及模糊測試參數(shù)配置預測等方面[11].
目前脆弱性檢測主要基于靜態(tài)分析的方法.在靜態(tài)分析的場景下,基于機器學習的脆弱性檢測方法可以分為基于詞法、基于語法、基于語義3個層次[12].
在基于詞法層的機器學習脆弱性檢測方法中,Neuhaus等人[13]提出組件引用是脆弱性代碼的特征,通過機器學習的方法從已知的脆弱性代碼中尋找規(guī)律性,以此來檢測脆弱性.Yamaguchi等人[14]提出了利用詞法分析來識別函數(shù)中的API(application programming interface)調用并通過API符號的詞嵌入向量來表示函數(shù),然后再用機器學習挖掘API調用和脆弱性代碼的關聯(lián)以檢測軟件脆弱性.Wijayasekara等人[15]發(fā)現(xiàn)在被公開報告和修補的bug中,有一些軟件并未進行修復的現(xiàn)象,提出一種利用文本挖掘技術從公開bug中來挖掘隱藏脆弱性的檢測方法.Mokhov等人[16]提出了一種用于靜態(tài)代碼分析和指紋識別的機器學習方法.Pang等人[17]提出了把N-gram方法和基于統(tǒng)計的特征選擇結合起來進行軟件脆弱性檢測的混合方法.
在基于語法層的機器學習脆弱性檢測方法中,Yamaguchi等人[18]提出一種從源代碼的抽象語法樹(abstract syntax tree, AST)中提取特征,再利用機器學習來進行脆弱性檢測的方法.該方法首先通過語法分析獲取源代碼的AST,再將AST映射到向量空間使其AST向量化,然后對大量的樣本進行基于奇異值分解(singular value decomposition, SVD)的主成分分析,從而得到矩陣形式的脆弱性結構模式,最后以結構模式為基礎,發(fā)現(xiàn)與脆弱性代碼具有相似結構模式的代碼函數(shù).Wang等人[19]提出了一種基于快速序列聚類的軟件脆弱性檢測方法,該方法利用基于密度的聚類方法對得到的脆弱性序列進行分類,有效地縮小了軟件脆弱性的檢測范圍,提高了脆弱性檢測的準確性和效率.
在基于語義層的機器學習脆弱性檢測方法中,Cheng等人[20]提出一種基于多子圖聯(lián)合進行代碼表征,并用其進行脆弱性檢測并定位的方法.Shar等人[21]針對基于機器學習的脆弱性檢測方法只能在文件級和模塊級對脆弱性進行檢測的不足,提出了將機器學習與基于靜態(tài)分析的脆弱性特征分析方法相結合的脆弱性檢測方法,該方法利用靜態(tài)污染傳播分析獲取脆弱性代碼的特征,然后使用機器學習方法學習SQL(structured query language)注入和跨站腳本攻擊(cross site scripting, XSS)脆弱性的模式,以檢測脆弱性.Yamaguchi等人[22]針對在函數(shù)調用時由于缺乏輸入檢查而導致的脆弱性的現(xiàn)象展開了研究,提出基于聚類分析來挖掘函數(shù)的輸入檢查模式,缺乏輸入檢測或者輸入檢測不正確的函數(shù)即為脆弱性,并提供修復建議.Medeiros等人[23]針對已有的污染傳播算法缺少對清理操作的識別而導致誤報的問題,通過機器學習對污染傳播分析的結果進行挖掘,獲取脆弱性誤報的模式,進而降低污染傳播檢測中的誤報率.
基于語義層的機器學習脆弱性檢測方法與其他2個層次的脆弱性檢測方法相比具有可檢測的脆弱性類型更多的優(yōu)勢,因此越來越多的研究者在語義層進行脆弱性分析的研究.在語義層的脆弱性檢測方法中,依據(jù)分析對象,可以將其分為基于二進制文件的脆弱性檢測[24-25]和基于源代碼的脆弱性檢測[23]2類.Grieco等人[24]提出一種在二進制文件上利用機器學習來檢測內存損壞的方法.但由于二進制代碼缺乏上層代碼的結構信息和類型信息等,很難與上層代碼建立對應關系,分析難度很大,因此基于二進制的代碼的脆弱性檢測算法相對較少.
基于源代碼的機器學習脆弱性檢測方法根據(jù)其檢測的粒度又可以將算法分為文件級、函數(shù)級、代碼段級3類.Shin等人[26]在文件級用復雜度、代碼變化和開發(fā)人員活動作為特征來刻畫脆弱性,并利用機器學習方法進行檢測.Li等人分別以API調用[27]、語義特征[28]等為中心,將源代碼切分成代碼段,并將代碼段的文本[29]或編譯[30]后的匯編代碼作為機器學習算法的輸入以進行脆弱性檢測.文件級的脆弱性檢測存在無法精確定位脆弱性的位置和脆弱性漏報率高的問題.而代碼段級的脆弱性檢測由于缺少完整的語法關系,很難得到代碼的語法結構信息,只能依賴源代碼的文本信息進行脆弱性檢測,但這會導致較高的漏報率和誤報率.我們希望找到一種能夠實現(xiàn)較高的脆弱性定位精度與較低的漏報率和誤報率的方法,因此選擇函數(shù)級作為算法的輸入粒度展開研究.
軟件脆弱性通常反映在源代碼的語法結構中,尤其是在函數(shù)級別,因此許多研究者在函數(shù)級對脆弱性檢測展開了研究.在基于機器學習的軟件脆弱性檢測方法中,數(shù)據(jù)預處理比分類器的選擇更為重要[31],如何將源代碼的文本表示形式轉化成可用于模型計算的向量表示形式是至關重要的一步.目前常用的代碼表征形式有代碼度量、Token序列、抽象語法樹和圖.抽象語法樹[32-33]和圖[34-37]與代碼度量和Token序列相比具有能保存更多代碼語法和語義信息的優(yōu)勢,因此大部分研究者利用抽象語法和圖對代碼進行表征.Lin等人[8]利用CodeSensor[18]工具對源代碼在函數(shù)級生成函數(shù)的抽象語法樹,將抽象語法樹進行深度遍歷得到函數(shù)的向量表示,并通過Word2vec將向量映射成數(shù)值型向量,然后通過Bi-LSTM和隨機森林的方法來進行脆弱性檢測.Liu等人[38]在Lin等人算法的基礎上引入遷移學習的框架來解決訓練樣本不足的問題.為了進一步解決訓練樣本不足和樣本不平衡的問題,Lin等人[39]又提出通過2個Bi-LSTM模型來利用SARD(software assurance reference dataset)數(shù)據(jù)解決數(shù)據(jù)不足問題,并通過調整權重和損失函數(shù)來解決樣本不平衡問題.Suneja等人[40]利用Joern工具生成函數(shù)的代碼屬性圖[41](即CPG,包括抽象語法樹信息、控制流信息和數(shù)據(jù)流信息的聯(lián)合圖型數(shù)據(jù)結構),然后將CPG圖作為函數(shù)的特征表示輸入到圖神經網絡中來進行脆弱性檢測.
以上方法都能從脆弱性代碼中學習到脆弱性代碼的特征,在函數(shù)級對未知脆弱性進行檢測,但在對多個軟件源代碼混合的真實數(shù)據(jù)集進行脆弱性檢測時,有較高的誤報率和漏報率.通過對現(xiàn)有方法和多個軟件的真實數(shù)據(jù)集進行研究分析,發(fā)現(xiàn)在現(xiàn)有方法在代碼表征過程中代碼的語法和語義信息存在較大的損失以及數(shù)據(jù)集中存在著嚴重的正負樣本不平衡現(xiàn)象,這是造成現(xiàn)有算法誤報率和漏報率較高的主要原因.
為了實現(xiàn)較高的脆弱性定位精度的軟件脆弱性檢測,需要在較細粒度實現(xiàn)脆弱性檢測.文件級的檢測粒度太粗,不滿足細粒度的要求.而代碼段級存在代碼段切分困難和易出現(xiàn)漏報、誤報的問題.函數(shù)級由于函數(shù)在源代碼中分隔明顯,具有易切分的優(yōu)勢.根據(jù)2006—2020年的Linux內核脆弱性數(shù)據(jù)顯示,在可獲取源代碼的1 037個脆弱性中有574個脆弱性在單個函數(shù)內.因此,本方法選擇以函數(shù)為單位進行特征提取和脆弱性檢測.
針對現(xiàn)有方法在多個軟件混合的真實數(shù)據(jù)集進行脆弱性檢測時誤報率和漏報率較高的現(xiàn)象,本文分析了現(xiàn)有方法中存在的問題并提出了改進方法.由于機器學習模型是數(shù)據(jù)驅動的,數(shù)據(jù)的提取方式和內容甚至比模型的選擇更加重要[9].現(xiàn)有的函數(shù)級的基于機器學習的軟件脆弱性檢測方法一般使用神經網絡和隨機森林2個模型,分別實現(xiàn)特征提取和脆弱性檢測的功能.這2個模型的輸入分別是代碼表征的結果和特征提取模型提取的代碼特征.因此為了提高在多個軟件混合的真實數(shù)據(jù)集上的脆弱性檢測能力,本文對代碼表征和模型提取2個階段展開研究.
通過對函數(shù)級的基于機器學習的軟件脆弱性檢測方法的代碼表征方式進行調查和研究發(fā)現(xiàn),現(xiàn)有方法主要是利用抽象語法樹對源代碼進行表征,但抽象語法樹缺少控制相關信息,存在著代碼語法和語義信息的損失的問題.為了降低代碼表征過程中語法和語義信息的損失,提高代碼表征的表征能力,需要選擇合適的表征方式對源代碼進行表征.代碼屬性圖[41]是一種用于代碼查詢的中間代碼表示.它將多個不同的程序表示合并到一個聯(lián)合圖數(shù)據(jù)結構中.代碼屬性圖本質是一個邊帶有標記的有向多重圖,整合了抽象語法樹、控制流圖(control flow graph, CFG)和程序依賴圖(program dependency graph, PDG)三種表示形式.由于代碼屬性圖含有的信息比單一抽象語法樹更加豐富和完整,因此本文選擇利用代碼屬性圖來進行代碼表征.
由于不同項目之間的編碼風格差異較大,直接利用函數(shù)的表征來進行脆弱性檢測效果較差,因此,在得到函數(shù)的代碼表征后,需要對代碼表征中的信息進行進一步提取和抽象,降低不同項目之間的編碼風格差異對檢測效果造成的影響,挖掘出隱藏在代碼表征中的脆弱性編程模式.在特征提取階段,現(xiàn)有方法通?;贐i-LSTM來構建特征提取模型,來挖掘代碼表征中的脆弱性特征.但Bi-LSTM模型參數(shù)較多,其訓練時間較長,同時也易出現(xiàn)過擬合現(xiàn)象.而Bi-GRU是Bi-LSTM的一種變體,與Bi-LSTM相比,Bi-GRU參數(shù)更少,具有訓練速度更快和不易過擬合的優(yōu)勢.因此本方法選擇利用Bi-GRU來構建特征提取模型.
針對2個階段存在的問題,改進代碼的表征方式,優(yōu)化特征提取模型,提出了一種基于代碼屬性圖和Bi-GRU的軟件脆弱性檢測方法.同時借助Joern工具本方法可以直接應用到實際的項目源代碼文件上,無需將項目源代碼切分成一個一個的函數(shù),由Joern工具自動生成函數(shù)的代碼屬性圖,因此本方法將數(shù)據(jù)預處理階段與代碼表征階段進行合并,在對代碼屬性圖中的信息進行提取時再進行相應預處理.本方法的整體框架示意圖如圖1所示,本方法通過3個步驟對待測軟件進行脆弱性檢測:1)代碼表征階段.利用Joern根據(jù)從源代碼中生成代碼屬性圖,并提取代碼屬性圖中的信息作為函數(shù)的表征.2)特征提取階段.利用基于Bi-GRU的特征提取模型提取函數(shù)表征中的脆弱性特征,獲得函數(shù)的特征向量.3)脆弱性檢測階段.利用隨機森林模型學習函數(shù)特征向量中的脆弱性特征,以此進行脆弱性檢測.
Fig. 1 Software vulnerability detection method based on code property graph and Bi-GRU圖1 基于代碼屬性圖和Bi-GRU的軟件脆弱性檢測方法
代碼屬性圖是一個圖形的數(shù)據(jù)結構,需要選擇合適的方式去提取代碼屬性圖中的信息.Suneja等人[40]利用圖神經網絡來學習代碼屬性圖的特征,進而挖掘脆弱性代碼的編程模式.但圖神經網絡更容易學習到圖的結構信息而忽略掉節(jié)點中的代碼等文本信息,并且將代碼屬性圖轉化成圖神經網絡的輸入所需要的處理過程更加復雜.為了合理利用代碼屬性圖中的信息,同時降低預處理的復雜度,本文選擇先將代碼屬性圖轉換成序列,然后以序列來表征函數(shù),最后再利用神經網絡模型提取序列中潛在的編程模式.
基于函數(shù)的代碼屬性圖的代碼表征過程如圖2所示.首先,從函數(shù)中生成函數(shù)的代碼屬性圖;然后,提取代碼屬性圖中的關鍵信息,將其轉化成序列;接著將文本形式的序列映射成數(shù)值型的向量并根據(jù)設置的長度,對向量進行填充和截斷操作保證向量長度一致;最后對向量進行詞嵌入處理,把向量中的每個元素替換成對應的詞向量,得到詞嵌入向量.通過以上4步就可以得到函數(shù)的基于代碼屬性圖的表征.
Fig. 2 Code representation extraction process based on code property graph圖2 基于代碼屬性圖的代碼表征提取過程
為了得到函數(shù)的代碼表征,首先需要生成每個函數(shù)的代碼屬性圖,本文通過Joern[10]工具從源代碼中生成代碼屬性圖.Joern是一個用于分析基于C/C++項目的開源工具,它不需要進行編譯和依賴庫就可以從整個項目或者單個源文件甚至函數(shù)代碼片段中提取每個函數(shù)的代碼屬性圖.本文以一個簡單的C語言函數(shù)為例,演示基于代碼屬性圖的代碼表征的過程.圖3所示的是一個C語言的函數(shù)fun1.
通過Joern工具可在圖3所示函數(shù)中抽取代碼屬性圖,如圖4所示.代碼屬性圖是一個有向圖,節(jié)點表示源代碼,這包括低級語言構造(如函數(shù)、變量和控制結構),也包括高級構造(如HTTP端點).每個節(jié)點都有一個類型,它是節(jié)點所表示的源代碼的類型,例如類型為“METHOD”的節(jié)點表示函數(shù),類型為“LOCAL”的節(jié)點表示局部變量的聲明.源代碼之間的關系通過相應節(jié)點之間的邊來表示.通過不同類型的邊,可以表示同一圖中的多種關系.邊有“AST”“CFG”“CDG”“DDG”等類型,其分別表示2個節(jié)點之間語法關系、控制關系、控制依賴和數(shù)據(jù)依賴等關系.
Fig. 4 A CPG of function fun1圖4 fun1函數(shù)生成的代碼屬性圖
在獲得函數(shù)的代碼屬性圖后,需要對代碼屬性圖中的信息進行進一步提取,將其轉化成向量的形式,以作為機器學習的輸入,同時最大程度地保留代碼的結構信息.在生成函數(shù)的代碼屬性圖之后,通過Joern將代碼屬性圖導出到Json文件中.代碼屬性圖在Json文件中的儲存形式如表1所示:
Table 1 Storage Form of fun1’s Code Property Graph in Json File表1 函數(shù)fun1的代碼屬性圖在Json文件中的儲存形式
在Json文件中,代碼屬性圖中的每個節(jié)點都存在編號、類型和代碼等信息,邊是通過連接的2個節(jié)點編號所表示的.由于程序依賴圖無法表示代碼行內部的語法結構,不適合用于代碼的結構化表征[42],因此只從代碼屬性圖中提取抽象語法樹序列和控制流圖序列來表征函數(shù).通過分析Json文件中的數(shù)據(jù)后發(fā)現(xiàn),節(jié)點編號順序含有了代碼屬性圖的結構信息,因此根據(jù)Json文件中節(jié)點的編號和各節(jié)點之間的關系,以[類型,代碼,類型,代碼,…]的排序方式,從代碼屬性圖中提取到抽象語法樹序列和控制流圖序列,以此來保存代碼的結構信息,提取過程如算法1所示.
算法1.代碼屬性圖序列提取算法.
輸入:cpg為代碼屬性圖;nodes為代碼屬性圖中的節(jié)點,有編號(id)、代碼(code)和類型(type)三種屬性;edges為代碼屬性圖中的邊,有入節(jié)點編號(node_in_id)、出節(jié)點編號(node_out_id)和類型(type)三種屬性.
輸出:AST為抽象語法樹序列,有節(jié)點編號序列(ids)和序列內容(tokens)兩個屬性;CFG為控制流圖序列,有節(jié)點編號序列(ids)和序列內容(tokens)兩個屬性.
①nodes,edges←cpg
/*從代碼屬性圖中提取出節(jié)點和邊*/
② foredgeinedges:
/*遍歷所有的邊*/
③ ifedge.type==“AST” andedge.node_in_idnot inAST.ids:
/*當邊為抽象語法樹的邊時,判斷邊的入節(jié)點編號是否在抽象語法樹序列的節(jié)點編號序列中*/
④node=nodes.find(edge.node_in_id);
/*如果邊的入節(jié)點編號不在抽象語法樹序列的節(jié)點編號序列中,則找到對應的節(jié)點*/
⑤AST.token.append(node.type,node.code);
/*在抽象語法樹序列的序列內容中加入對應節(jié)點的類型和代碼*/
⑥AST.ids.append(node.id);
⑦ else ifedge.type==“AST” andedge.
node_out_idnot inAST.ids:
/*當邊為抽象語法樹的邊時,判斷邊的出節(jié)點編號是否在抽象語法樹序列的節(jié)點編號序列中*/
⑧node=nodes.find(edge.node_out_id);
/*如果邊的出節(jié)點編號不在抽象語法樹序列的節(jié)點編號序列中,則找到對應的節(jié)點*/
⑨AST.token.append(node.type,node.code);
/*在抽象語法樹序列的序列內容中加入對應節(jié)點的類型和代碼*/
⑩AST.ids.append(node.id);
node_in_idnot inCFG.ids:
/*當邊為控制流圖的邊時,判斷邊的入節(jié)點編號是否在控制流圖序列的節(jié)點編號序列中*/
/*如果邊的入節(jié)點編號不在控制流圖序列的節(jié)點編號序列中,則找到對應的節(jié)點*/
/*在控制流圖序列的序列內容中加入對應節(jié)點的類型和代碼*/
node_out_idnot inCFG.ids:
/*當邊為控制流圖的邊時,判斷邊的出節(jié)點編號是否在控制流圖序列的節(jié)點編號序列中*/
/*如果邊的出節(jié)點編號不在控制流圖序列的節(jié)點編號序列中,則找到對應的節(jié)點*/
/*在控制流圖序列的序列內容中加入對應節(jié)點的類型和代碼*/
為了更好地保留代碼的語義信息,需對節(jié)點的源代碼進行進一步處理.在程序的源代碼中往往含有很多長短不一的字符串常量,而程序源代碼中的字符串常量并不影響程序的功能,為了降低字符串常量對代碼表征的影響,將代碼中的所有字符串用“str”進行替換,如語句中存在“printf(“test”)”,將其進行替換后為“printf(“str”)”.節(jié)點中的源代碼是以字符串的形式進行儲存,需要對字符串進行分割,將變量、操作符、關鍵字分隔開,使轉化后的序列語義正確,如在節(jié)點中的源代碼是“intx”,將其按變量類型和變量分隔開變成“int”和“x”兩個詞,如表2所示,函數(shù)fun1的抽象語法樹序列為[METHOD,fun1,PARAM,int,x,…],控制流圖序列為[METHOD,fun1,test2,test2(x),operator.assignment,y,=,test2,(,x,),…].將控制流序列和抽象語法樹序列合并得到的文本型向量可唯一的標識fun1函數(shù).本文將從代碼屬性圖中得到的控制流序列和抽象語法樹序列組成的文本型向量稱為ACS(abstract syntax tree and control flow graph sequence),每一個函數(shù)都可被唯一的ACS表示.
Table 2 Motivating Examples of How Function fun1 is Converted to AST and CFG in Serialized Format
由于后續(xù)的機器學習算法不能識別文本型向量,只能以數(shù)值型向量作為輸入,因此需要將文本型向量轉化成數(shù)值型向量.為了獲取機器學習算法能識別的輸入,需要構建一個映射來將向量的每個文本元素鏈接到一個整數(shù).這些整數(shù)充當“標記”,唯一地標識每個文本元素.例如,將類型“METHOD”映射到“1”,將變量“fun1”映射到“2”,以此類推.通過用數(shù)字標記替換向量的文本元素,它們的序列保持不變.本方法通過keras分詞器Tokenizer來實現(xiàn)這一功能,Tokenizer是一個用于向量化文本或將文本轉換為序列的類,利用Tokenizer可以將由抽象語法樹序列和控制流圖序列組成的文本型向量轉換成數(shù)值型的向量,如圖1所示,通過Tokenizer可將文本型向量(METHOD,fun1,PARAM,int,x,…)轉化成數(shù)值型向量(1,2,25,…).
由于機器學習模型的輸入為同一長度的向量,為了統(tǒng)一輸入向量的長度,需要對向量進行填充和截斷.由于每個函數(shù)的大小不一樣,得到的向量長度會不一樣,2個不同函數(shù)的ACS長度可能還差別很大.為了平衡向量的長度和過稀疏性,應該選擇一個合適的長度來填充/截斷.對于長度大于L的向量,在對向量末端大于的部分進行截斷,對于短向量,在向量末段使用零來填充,使所有向量長度統(tǒng)一為L.
為了更好地保留代碼的語義信息,對向量需要使用詞嵌入進行處理.詞嵌入將輸入序列中的每個“詞”表示為一個固定維數(shù)的向量.傳統(tǒng)的嵌入方法可能將代碼中的變量、類型或操作符(如“+”和“-”)轉換為任意維向量,而忽略各個詞之間可能存在的關系.Lin等人[8]通過將Word2vec的連續(xù)Bag-of-Words(continuous bag-of-words, CBOW)模型生成的詞向量投影到二維平面上發(fā)現(xiàn),語義相近的詞在平面上的位置是相近的,這表明Word2vec的CBOW模型能較好地保留詞之間的關系,進而保留代碼語義.因此,本文也采用這種方式保留代碼語義.
本文利用所有函數(shù)的文本型向量組成的語料庫對Word2vec模型進行訓練,得到映射集,在映射集中語料庫中每一個出現(xiàn)頻次達到閾值的詞都會有一個唯一對應的N維的詞向量.本方法通過在特征提取模型中加入映射層來實現(xiàn)向量的詞.利用映射集將向量中的每個元素轉換為N維的詞向量,當元素沒有對應的詞向量時,使用全零的N維向量作為當前元素的詞向量.
本文利用了循環(huán)神經網絡(recurrent neural network, RNN)可以保留序列順序信息和降維的特點,來挖掘多個軟件源代碼的深層順序特征.在RNN的基礎上,采用一個由RNN、全局最大池化層、Dropout層和密集層組成的模型來提取抽象語法樹和控制流圖中的潛在序列特征.
RNN能夠提取復雜的序列中的順序信息,這使RNN廣泛用于順序相關數(shù)據(jù)的預測任務中.對于給定的時間步長t,RNN的輸出yt不僅取決于當前的輸入xt,還取決于時間步長t-1之前的累積信息.該特性為RNN提供了為當前預測保留過去有用信息的能力,從而使其成為解決NLP問題的強大工具.ACS的元素之間的順序關系與自然語言中的上下文有很強的相似性,因此將RNN應用到本文場景中.因為ACS反映了代碼樣本的結構信息,所以改變任何元素的序列都會改變結構和語義含義.例如,向量(METHOD,fun1,PARAM,int,x,…)表示fun1函數(shù)有一個int類型的參數(shù)x.在改變“METHOD”和“PARAM”的序列后,向量(PARAM,fun1,METHOD,int,x,…)在語義上變得沒有意義,參數(shù)聲明應該跟在函數(shù)后.因此,本文將通過基于RNN的方法來提取脆弱性代碼中的隱藏順序特征,挖掘脆弱性源代碼的編程模式.
通常,函數(shù)中的脆弱性代碼的編程模式可以與許多行代碼相關聯(lián).當將函數(shù)映射到向量時,與脆弱性相關的模式與向量的多個元素相關.標準的RNN能夠處理短期依賴關系,比如元素“METHOD”后面應該接函數(shù)名“fun1”,但是在處理長期依賴關系時,比如捕捉與許多連續(xù)或間歇元素相關的脆弱性編程模式,標準的RNN無法處理.因此,使用RNN的變體Bi-LSTM和Bi-GRU來捕獲長期依賴,以獲取脆弱性代碼的高級表示.
LSTM(long short-term memory)由輸入門、輸出門、遺忘門、細胞狀態(tài)等構成.LSTM通過對細胞狀態(tài)中的信息遺忘和記憶新的信息以保留對后續(xù)計算有用的信息和丟棄無用的信息,從而達到處理長期依賴的目的.Bi-LSTM其本質是一個雙向的LSTM,可以同時處理前向和后向2個方向上的信息.對于時刻t的輸出,前向LSTM層具有輸入序列中時刻t以及之前時刻的信息,而后向LSTM層中具有輸入序列中時刻t以及之后時刻的信息.通過Bi-LSTM可以有效地保留ACS的順序特征,使神經網絡模型可以學習到代碼的結構信息.
GRU(gated recurrent unit)是LSTM的一種變體,它比LSTM的結構更簡單,訓練速度更快.在GRU中只有更新門和重置門,更新門決定時刻t以前的信息對當前時刻t產生的影響,而重置門決定如何將時刻t的輸入信息與時刻t之前的累積信息相結合.通過門機制,GRU也可以提取序列中的長期依賴關系.Bi-GRU可以同時處理雙向的順序信息,因此通過Bi-GRU可以很好地挖掘代碼中的結構信息,在數(shù)據(jù)量較少時,Bi-GRU的表現(xiàn)比Bi-LSTM更加優(yōu)異.
為了避免出現(xiàn)過擬合現(xiàn)象,增強模型的魯棒性,本方法在特征提取模型中加入Dropout層.Dropout[43]是在深度學習中用來緩解過擬合的一種手段,在一定程度上可以達到正則化的效果.它可以根據(jù)數(shù)值的閾值p,在每個訓練批次中,隨機選擇隱藏層中的部分節(jié)點失效,以減少隱藏層節(jié)點之間的相互作用,達到減少過擬合現(xiàn)象的作用.由于在真實數(shù)據(jù)集中,脆弱性函數(shù)的數(shù)量較少,存在樣本不平衡的問題,在進行模型訓練時易出現(xiàn)過擬合現(xiàn)象.因此,嘗試在模型中加入Dropout層來緩解過擬合,以達到更好的效果.
由于Bi-GRU和Bi-LSTM在不同場景中各有優(yōu)劣,為了更好地挖掘到代碼中的深層特征,達到更好的檢測效果,利用Bi-LSTM,Bi-GRU和Dropout構建多個模型,尋找特征提取效果最好的模型.通過在LibTIFF數(shù)據(jù)集上的初步實驗發(fā)現(xiàn),與基于Bi-LSTM的特征提取模型相比,基于Bi-GRU的特征提取模型脆弱性檢測的準確率與召回率提高了5%以上,因此本方法選擇利用Bi-GRU構建特征提取模型,模型結構如圖5所示,在全局最大池化層之后增加Dropout層和密集層,形成一個完整的網絡.由于脆弱性檢測是一個二分類問題,因此設置特征提取模型的訓練損失函數(shù)為二分類的交叉熵(binary_cross_entropy).在特征提取模型的訓練階段,使用不同軟件項目的已知脆弱性代碼混合的數(shù)據(jù)集訓練特征提取模型.通過這些軟件項目可以初始化網絡參數(shù),以學習脆弱性代碼的低級特征.訓練輸入是從ACS映射得到的數(shù)值型向量.輸入數(shù)據(jù)被分為訓練集和驗證集,用于構建和評估模型,并指導模型調優(yōu)過程,以實現(xiàn)性能最大化.
盡管特征提取模型也可實現(xiàn)對代碼進行脆弱性檢測的功能,但在真實情況中,脆弱性代碼在軟件源代碼中所占比重較低,存在著正負樣本不均衡的問題,特征提取模型無法處理這一問題,導致特征提取模型的脆弱性檢測能力較弱,誤報率高,因此本方法只使用特征提取模型提取代碼中的脆弱性特征,通過其他集成學習的方法來進行脆弱性檢測,以降低正負樣本不平衡帶來的影響.在特征模型訓練完成后,用經過預處理的從目標項目生成的數(shù)值型向量(帶有有限標簽)提供給訓練好的網絡,并從網絡的池化層獲得學習到的表示.給定一個長度L的序列作為網絡的輸入,學習到的表示是一個Z維的向量,稱為函數(shù)的特征向量.
Fig. 5 The architecture of Bi-GRU network for learning deep CPG representations圖5 學習深層CPG表示的Bi-GRU網絡結構
在得到函數(shù)的特征向量后,需要進一步對特征向量中的脆弱性特征進行學習,以達到脆弱性檢測的目的.由于在訓練集中的脆弱性函數(shù)較少,大部分分類方法無法從訓練集中學到脆弱性特征進行脆弱性檢測,而隨機森林是一個通過對訓練集的多次采樣構建多棵決策樹來進行分類的集成分類器,有助于解決數(shù)據(jù)不平衡的問題,因此選擇隨機森林作為脆弱性檢測器,學習從神經網絡中得到的特征表示.由于現(xiàn)實中,脆弱性代碼只占所有代碼中很小的一部分,所以數(shù)據(jù)集會存在嚴重的正負樣本不平衡的現(xiàn)象,因此將隨機森林的class_weight參數(shù)設置為“balanced”,盡量降低代碼不平衡帶來的影響.本文利用少量帶標簽的特征向量對脆弱性檢測器模型進行預訓練,然后利用測試集來測試整個方法的脆弱性檢測能力.
當使用脆弱性檢測器來檢測時,脆弱性檢測器會輸出每個代碼樣本可能為脆弱性代碼的概率.通過對測試集中所有函數(shù)為脆弱性代碼的概率進行排序,即可得到項目中最可能為脆弱性代碼的函數(shù).
使用本文提出的方法構建了一個基于代碼屬性圖的軟件脆弱性檢測模型.本節(jié)將介紹對本文方法檢測能力進行評價的度量標準以及評測數(shù)據(jù)集的構成和來源,并分別從ACS向量長度、代碼表征方式和特征提取模型等方面驗證本文所提出方法的有效性.
本文所有實驗在一臺配置為GPU(GeForce RTX 2060 SUPER),CPU(i7 10700,8核16線程)的計算機上進行,操作系統(tǒng)為Ubuntu18.04.4 LTS,內核為Linux kernel 4.18,采用Joern1.29進行代碼解析,編程語言為Python3.7,GPU加速環(huán)境為CUDA10.1,cudnn7.6.5,相關依賴包分別為tensor-flow2.2.0,pandas1.0.1,gensim3.8.3,numpy1.18.1,h5py2.10.0,ijson3.1.2,Keras_Preprocessing1.1.2.
本文方法的檢測能力是通過以真實漏洞函數(shù)在函數(shù)列表所占比例來評測的,該列表根據(jù)模型預測的函數(shù)為脆弱性的概率進行排序.因此,方法的檢測能力評估指標是top-k精度(記為P@K)和top-k召回(記為R@K).這些指標通常用于信息檢索系統(tǒng)的上下文,如搜索引擎測量檢索到的實際有關的文件在檢索文檔所占比例.在本實驗中,P@K指top-k檢索函數(shù)中脆弱性函數(shù)所占比例,其中R@K表示在檢索到的前k個函數(shù)中脆弱函數(shù)所占的比例.P@K和R@K計算為
(1)
(2)
其中,TP@k為返回的k個樣本中最有可能出現(xiàn)脆弱性的真實正樣本,即實際發(fā)現(xiàn)的脆弱性函數(shù);FP@k和FN@k分別為在k個樣本中檢索到的假陽性和假陰性樣本.在實際情況下中,脆弱性函數(shù)的數(shù)量與非脆弱性函數(shù)的數(shù)量相比少很多.當檢索top-k函數(shù)時,期望檢索盡可能多的脆弱函數(shù).在本實驗中,將k設置成是一個在10~200之間的可調整數(shù),以模擬由于時間和資源的限制而檢索到的函數(shù)數(shù)量有限的實際情況.
為了構建驗證改進代碼表征方式對于脆弱性檢測效果提升的消融實驗(ablation experiment),本文實驗選擇以抽象語法樹作為代碼表征方式的Lin等人[8]的方法作為對比對象.由于應用場景不同或不符合消融實驗的原則等原因,本文方法不與其他基于機器學習的函數(shù)級脆弱性檢測方法[38-40]進行對比.
為了與Lin等人[8]的工作進行比較,本文實驗在Lin等人[8]構建的脆弱性數(shù)據(jù)集上進行.脆弱性數(shù)據(jù)集包含來自6個開源項目的脆弱性和非脆弱性的函數(shù),包括FFmpeg,LibTIFF,LibPNG,Pidgin,VLC Media Player和Asterisk,已被按函數(shù)切分并做了標記.該數(shù)據(jù)級脆弱性函數(shù)的標簽是根據(jù)美國國家漏洞數(shù)據(jù)庫(National Vulnerability Database, NVD)[1]和公共脆弱性數(shù)據(jù)庫(Common Vulnerability and Exposure, CVE)[44]網站的數(shù)據(jù)進行標記的.該數(shù)據(jù)集中丟棄了跨多個函數(shù)或多個文件的脆弱性;除去已知的脆弱性函數(shù),將剩余的函數(shù)視為非脆弱性函數(shù).通過這些函數(shù)級的脆弱性數(shù)據(jù)可以在函數(shù)級構建脆弱性檢測器,從而實現(xiàn)比在文件更細粒度的檢測能力.在數(shù)據(jù)集中,所有的脆弱性函數(shù)的源代碼的文件名中會含有脆弱性的CVE編號,因此將所有所在文件的文件名含有“CVE”字符串的函數(shù)標記為脆弱性函數(shù),其余全部標記為非脆弱性函數(shù).由于預處理方式的不同,從上述6個開源項目中獲得的脆弱性代碼樣本數(shù)量和非脆弱性代碼樣本數(shù)量如表3所示.
Table 3 The Number of Vulnerability Functions in the Dataset表3 數(shù)據(jù)集中脆弱性函數(shù)數(shù)量
FFmpeg,LibTIFF,LibPNG這3個軟件中脆弱性函數(shù)所占比例較高,有利于構建訓練集和測試集,因此本文將分別使用這3個數(shù)據(jù)集作為待測軟件,對本文方法進行測試.當選定好待測軟件后,利用其他5個軟件的數(shù)據(jù)對特征提取模型進行訓練,然后將待測軟件的數(shù)據(jù)劃分成訓練集和測試集,通過訓練集訓練脆弱性檢測模型,并提供測試集對方法的脆弱性檢測能力進行測試.
為模擬單一軟件中已知脆弱性較少的實際情況,在這組實驗中,在刪去一部分由于函數(shù)切分錯誤導致無法提取代碼屬性圖的函數(shù)后,將數(shù)據(jù)樣本分為:30%的訓練數(shù)據(jù)和70%的測試數(shù)據(jù),經過本文方法和Lin的方法處理后,得到脆弱性函數(shù)數(shù)量和非脆弱性函數(shù)數(shù)量如表4所示.將訓練集和測試集提供給訓練好的特征提取模型來生成函數(shù)的特征向量,該模型是使用除待測軟件外的其余5個軟件的所有數(shù)據(jù)集進行訓練,使用池化層的輸出作為函數(shù)的特征向量.由訓練集生成的特征向量將直接作為訓練隨機森林分類器的訓練集;由測試集生成的特征向量作為測試集來測試訓練過的隨機森林分類器.
Table 4 The Number of Vulnerability Functions in the Training Set and Test Set表4 訓練集和測試集中脆弱性函數(shù)數(shù)量
6.3.1 ACS最大長度的設定
由于不同函數(shù)的ACS長度差別較大,L的取值會影響到脆弱性檢測的效果,該實驗通過變化的取值判斷其取何值時方法的脆弱性檢測效果最好,以確定ACS的默認長度.
通過LibTIFF,LibPNG,Pidgin,VLC Media Player和Asterisk等5個項目的數(shù)據(jù)對基于Bi-LSTM的特征提取模型進行訓練,模型參數(shù)如表5所示:
Table 5 Parameters of Feature Extraction Model表5 特征提取模型的參數(shù)
Fig. 6 Results of different ACS lengths on FFmpeg圖6 不同ACS長度在FFmpeg上的結果
利用一部分FFmpeg項目的數(shù)據(jù)對基于隨機森林的脆弱性檢測模型進行訓練,然后將剩余部分作為測試集測試模型效果,結果如圖6所示.從圖6中可知,在前10、前20、前40、前50和前200個方法預測的最可能的脆弱性函數(shù),當L=2 000時,方法預測的真實脆弱性函數(shù)的數(shù)量最多,同時整體效果最好,因此在后面的實驗中設置L=2 000.
6.3.2 與已有表征方法的對比實驗
本實驗通過對比不同表征方式對軟件脆弱性檢測效果的影響,以驗證基于代碼屬性圖的表征方式的有效性.Lin等人[8]利用CodeSensor[16]提取抽象語法樹對代碼進行表征,AST是以代碼屬性圖中的抽象語法樹作為函數(shù)的表征方式,ACS是以代碼屬性圖中的抽象語法樹序列和控制流圖序列作為函數(shù)的表征方式,其特征提取階段使用基于Bi-LSTM(無Dropout層)的特征提取模型提取特征,以隨機森林作為脆弱性檢測模型,由于不同表征方式生成的代碼表征長度差別較大,本實驗根據(jù)Lin,AST和ACS等3種代碼表征方式在FFmpeg數(shù)據(jù)集上的檢測效果,將特征提取模型輸入長度分別設置成1 000,1 500,2 000,其余參數(shù)如表5所示.本文在FFmpeg,LibTIFF,LibPNG等3個數(shù)據(jù)集上,對3種表征方式的表征能力進行檢測,其結果如表6所示.表6中加粗的數(shù)據(jù)為當前在3種基于不同表征方式的方法中表現(xiàn)最好的結果.
Table 6 The Results of Three Characterization Methods on Different Data Sets表6 3種表征方式在不同數(shù)據(jù)集上的結果
從表6中可以看出,與其他方法相比,以ACS作為表征方式的P@K和R@K在3個數(shù)據(jù)集中都是最高的.在LibPNG數(shù)據(jù)集上,基于ACS的方法預測的前50個最可能的脆弱性函數(shù)中包含了LibPNG中所有的脆弱性函數(shù),其R@K達到了100%.與Lin等人[8]的方法相比,基于ACS的方法的P@K和R@K最大提高了30%和18%,而與基于AST的方法相比,基于ACS的方法的P@K和R@K最大提高了17%和8%.實驗結果表明,在FFmpeg,LibPNG和LibTIFF數(shù)據(jù)集上,以ACS作為表征方式時,方法的脆弱性檢測效果優(yōu)于另外2種表征方式.
為了更直觀地對比3種方法的結果,我們將3種方法在3個數(shù)據(jù)集上的精確率可視化成折線圖,如圖7所示.從圖7(a)中可以看出,以ACS作為表征方式的方法預測的前10~150個最可能的脆弱性函數(shù)的P@K一直高于另外2種方法,在預測的前40個最可能的脆弱性函數(shù)中,以ACS為表征方式的方法比Lin等人[8]和以AST為表征方式的方法的P@K分別高28%和15%.從圖7(b)中可知,在以LibTIFF作為待測軟件時,基于ACS的方法預測的前20個最可能的脆弱性函數(shù)的P@K為100%,比另外2種方法表現(xiàn)更加優(yōu)異.從圖7(c)可知,基于ACS的方法在LibPNG數(shù)據(jù)集上預測的最可能前30個最可能的脆弱性函數(shù)P@K一直高于90%,與Lin等人[8]的方法相比,P@K提高了10%.
6.3.3 不同特征提取模型的脆弱性檢測效果對比
本節(jié)將對比不同特征提取模型的脆弱性檢測效果,以找到最合適的特征提取模型.我們基于Bi-LSTM,Bi-GRU和Dropout構建4個模型.4個特征提取模型的整體結構與圖5的結構類似,模型參數(shù)如表5所示,Bi-LSTM_1的結構與圖5相比,刪去了Dropout層,并將Bi-GRU替換成了Bi-LSTM,而Bi-LSTM_2則只是將Bi-GRU替換成了Bi-LSTM,Bi-GRU_1與圖5的結構相比,刪去了Dropout層,而Bi-GRU_2的結構與圖5的結構一致.
本實驗分別將FFmpeg,LibTIFF,LibPNG這3個數(shù)據(jù)集作為待測軟件對特征提取模型進行測試.在FFmpeg上進行測試時,從特征提取模型中獲取FFmpeg數(shù)據(jù)集的特征向量,再用FFmpeg中訓練集的特征向量訓練脆弱性檢測模型,最后用FFmpeg中的測試集來測試模型的脆弱性檢測效果,其結果如表7所示.
Fig. 7 Detection performance comparison of three characterization methods圖7 3種表征方式的檢測性能比較
Table 7 The Results of Four Feature Extraction Models on Different Datasets表7 4種特征提取模型在不同數(shù)據(jù)集上的結果
從表7中可以得到,與Bi-LSTM_1相比,以Bi-GRU_2為特征提取模型的方法的P@K和R@K最大提高了10%和6%,同時由于Bi-GRU模型的參數(shù)更少,其訓練時間會比Bi-LSTM模型的訓練時間更少.因此,本方法使用Bi-GRU加Dropout層作為特征提取模型來進行特征提取.
Fig. 8 Detection performance comparison of four feature extraction models圖8 4種特征提取模型的檢測性能比較
將4個特征提取模型在3個數(shù)據(jù)集上的精確率繪制成折線圖,如圖8所示.從圖8(a)可以看出,在FFmpeg數(shù)據(jù)集上,方法預測的10~150個最可能的脆弱性函數(shù)中,以Bi-GRU_2為特征提取模型的方法的R@K為最高的次數(shù),同時在其預測的前150個最可能的脆弱性函數(shù)中,真正的脆弱性函數(shù)的數(shù)量達到了69個,占到了FFmpeg中脆弱性函數(shù)總數(shù)量的48%.在圖8(b)(c)中可知,以Bi-GRU_2為特征提取模型的方法的R@K一直高于其他3種特征提取模型.在LibTIFF數(shù)據(jù)集上,以Bi-GRU_2為特征提取模型的方法預測前40個最可能的脆弱性函數(shù)的R@K達到了100%,優(yōu)于其他3個模型.在LibPNG數(shù)據(jù)集上,以Bi-GRU_2為特征提取模型的方法預測的前40個最可能的脆弱性函數(shù)包含了LibPNG測試集中全部的33個脆弱性函數(shù),R@K達到了100%.同時從圖8中可知,在FFmpeg,LibTIFF和LibPNG這3個數(shù)據(jù)集上,Bi-LSTM_1的檢測效果優(yōu)于Bi-LSTM_2,這表明在Bi-LSTM的模型中加入Dropout層并沒有帶來效果提升,這是由于Bi-LSTM的參數(shù)較多,而數(shù)據(jù)集中脆弱性樣本較少,加入Dropout層后,反而參數(shù)不能及時得到更新,從而導致檢測效果變差,而Bi-GRU_2的檢測效果優(yōu)于Bi-GRU_1,這表明在Bi-GRU中加入Dropout層后能夠提升檢測效果,這是因為Bi-GRU中所含有的參數(shù)更少,加入Dropout層后反而能有效地學習到脆弱性函數(shù)的特征,增強模型的泛化能力.
6.3.4 不同方法的時間性能的比較
本節(jié)主要比較本文方法和Lin等人[8]方法在時間方面的性能.從表8中可以看出,本方法與Lin等人[8]的時間開銷主要是模型訓練階段和預處理階段,在檢測階段的時間差別不大.同時Lin等人[8]的方法必須先將項目文件中的函數(shù)提取出來,生成每個函數(shù)獨立的代碼文件,才能作為方法的輸入.而VDCPG可直接輸入項目中的代碼文件,無需切分.本文的數(shù)據(jù)集是已經將源代碼根據(jù)函數(shù)切分好的數(shù)據(jù)集,沒有計算函數(shù)切分的時間,因此2種方法在實際情況中時間的開銷會更接近.與增加的精確率和召回率而言,增加的時間開銷是可接受的.
Table 8 Comparison of Time Performance
本文針對現(xiàn)有方法在多個軟件混合的真實數(shù)據(jù)集進行脆弱性檢測時誤報率和漏報率較高的現(xiàn)象,在代碼表征和特征提取階段展開了研究,發(fā)現(xiàn)現(xiàn)有方法存在代碼表征方式表征能力不足的問題,通過改進代碼表征方式,提高表征方式的表征能力,優(yōu)化特征提取模型,增強特征提取模型的特征提取能力,提出了一種基于代碼屬性圖和Bi-GRU的軟件脆弱性檢測方法.實驗結果表明,本文提出的基于代碼屬性圖和Bi-GRU的軟件脆弱性檢測方法可提高面向多個軟件源代碼混合的真實數(shù)據(jù)集的脆弱性檢測效果,降低誤報率和漏報率.