梁樹彬,鄭 力,鐘 杰,胡 勇
(1.四川大學 網絡空間安全學院,四川 成都 610207;2.中物院成都科學技術發展中心,四川 成都 610299)
信息化的推進使得軟件系統功能愈加復雜,而由設計缺陷和實現錯誤引起的軟件漏洞不可避免。頻發的軟件安全事件和持續增長的披露漏洞數表明軟件安全形勢仍然十分嚴峻。源代碼漏洞檢測是提升軟件質量與安全性,以及減少漏洞數和降低漏洞修復成本的重要手段,通常與軟件開發生命周期緊密結合。在開發階段,源代碼漏洞檢測對源代碼進行靜態分析,檢查編碼錯誤和潛在的漏洞等;在測試階段,源代碼漏洞檢測對可執行文件進行動態分析,測試軟件實際運行時可能出現的問題。
靜態分析在不運行軟件的情況下對源代碼進行分析來檢測代碼缺陷。常見的靜態分析技術包括詞法分析、數據流分析、符號執行、模型檢查、定理證明等,但依賴于專家制定規則,存在主觀性較強,規則不完善等問題。動態測試執行目標程序并監控其運行狀況來挖掘漏洞,由于獲取了具體的運行信息,其誤報率較低,通常使用模糊測試、動態污點分析等方法,但其存在分析效率低和代碼覆蓋率低導致的漏報率高、資源消耗大、復雜漏洞難以發現等問題。
上述的漏洞檢測方法各有其局限性,一般僅適用于小規模軟件,在面對大規模且復雜度較高的軟件系統時,通常無法滿足安全性分析需求,因此,如何在大規模且復雜的軟件系統中快速、準確地檢測漏洞成為軟件安全領域亟待解決的問題之一。
2012 年,Hindle 等人[1]使用N元語言模型對源代碼進行建模,表明編程語言與自然語言有相似的可預測的統計學特性,并提出代碼自然性假設。受到代碼自然性假設的啟發,研究人員開始將自然語言處理技術應用于源代碼,通過神經網絡對代碼的詞法、語法和語義特征進行提取,進而檢測漏洞,解決靜態分析誤報率高的問題。
本文針對現有基于循環神經網絡的方法存在訓練速度慢、可解釋性差等問題,提出結合卷積神經網絡和高速神經網絡[2]的源代碼漏洞檢測模型,主要工作包括兩個方面:
(1)使用基于語義的漏洞候選(Semantics-based Vulnerability Candidates,SeVC)[3]作為代碼表征,其基于程序依賴圖(Program Dependency Graph)對代碼進行切片,去除與漏洞無關的冗余信息,保留數據依賴和控制依賴信息;使用卷積神經網絡提取代碼的局部特征,結合高速神經網絡進行特征變換,學習代碼的抽象語義特征。實驗結果表明,本文提出的模型能大幅降低漏報率,有效提升準確率、F1 分數和馬修斯相關系數[4](Matthews Correlation Coefficient,MCC)等指標。
(2)針對現有方法可解釋性較低的問題,使用顯著圖[5](Saliency map)對模型檢測結果進行解釋,實驗結果表明,根據顯著圖得出的重要性分數不能準確反映漏洞的成因及位置,但能反映出對預測結果重要的代碼元素,可以輔助人工驗證及修復漏洞。
源代碼本質上屬于文本信息,于是自然語言處理中使用的技術被應用于源代碼漏洞檢測,通常利用循環神經網絡來提取源代碼中的語義特征,從而進行漏洞檢測。
Li 等人[6]提出包含數據依賴信息的代碼片段(code gadget)作為代碼表征,使用雙向長短期記憶網絡(Bidirectional Long Short-Term Memory,BLSTM)模型檢測特定的code gadget 是否含有漏洞,但code gadget 只包含數據依賴信息,于是Li 等人[3]提出基于語義的漏洞候選作為代碼表征,包含數據依賴和控制依賴信息,實驗結果表明加入數據依賴和控制依賴信息的模型能平均降低誤報率30.4%。Li 等人[7]還認為基于源代碼的表征不能充分表現控制流信息和變量之間的關系,一些語義上的信息不能被其捕獲,所以提出了基于中間代碼的代碼表征基于中間表示和語義的漏洞候選(intermediate code-and Semantics-based Vulnerability Candidate,iSeVC),充分捕獲代碼的語義信息,并實現漏洞的細粒度定位。相比SeVC,使用iSeVC 代碼表征的模型誤報率降低了1.7%,漏報率降低了28.8%。Cao 等人[8]先對源代碼進行離散傅里葉變換將其轉化到頻率域,再使用卷積神經網絡(Convolutional Neural Network,CNN)和BLSTM 在頻率域捕獲局部和全局特征,將其進行逆傅里葉變換后使用注意力機制捕獲重要的信息,并利用注意力分數對模型預測結果解釋。Zou 等人[9]在code gadget 的基礎上引入控制依賴信息,提出代碼注意力(code attention),并使用BLSTM 模型實現40 種通用缺陷枚舉(Common Weakness Enumeration,CWE)類型的檢測,相比code gadget,漏報率降低12.27%。上述方法主要使用循環神經網絡來構建模型,訓練速度較慢,而Tang 等人[10]使用極限學習機(Extreme Learning Machines)并結合核方法來構建模型,在加速模型訓練的同時提升模型精確率。
現有的方法主要存在兩個問題:基于循環神經網絡的方法的訓練與預測速度較慢;大多數方法可解釋性較差,對源漏洞檢測模型的可解釋性研究較少。因此,本文提出結合高速神經網絡的卷積神經網絡(CNN with Highway,CNNH)模型,提升學習效率和效果,并使用顯著圖對模型預測結果進行解釋,確定與漏洞相關的代碼元素,輔助人工驗證與修復漏洞。
如圖1 所示,本文所提源代碼漏洞檢測方法的整體流程為,先對切片后的代碼進行符號化,去除標識符信息;再訓練神經網絡模型;然后,在預測時使用訓練好的模型得到檢測結果,并使用顯著圖對模型預測結果進行解釋;最后,確定每個代碼元素對預測結果的重要性分數。

圖1 漏洞檢測流程
本文使用SeVC 作為代碼表征,包含代碼的數據依賴和控制依賴信息。數據的預處理主要分為標識符符號化和代碼分詞兩個步驟。
標識符符號化步驟中,用戶定義的標識符與漏洞無關,將其轉化為符號表示可減小單詞表的規模,提升訓練效率。此外,數據樣本的函數名包含標簽信息,需對其進行符號化消除標簽信息。根據切片中變量的出現順序將變量重命名為variable_0,variable_1 等。根據切片中函數出現的順序,將函數重命名為func_0,func_1 等,標識符符號化示例如圖2 所示,其中敏感操作,比如memcpy、strcat等不進行符號化。

圖2 標識符符號化示例
代碼分詞步驟中,將符號化的切片進行分詞,將其轉化為代碼元素序列。
源代碼是文本信息,與自然語言文本類似,都具有局部的特征結構,而卷積神經網絡具有局部連接的特性,非常適合提取代碼局部的特征。本文使用多尺度的卷積神經網絡來提取代碼的局部特征,并使用高速神經網絡將局部特征組合起來形成高層、抽象的代碼特征。
本文基于Kim[11]的網絡模型架構進行改進,采用4 種卷積核大小的卷積層,并加大卷積核尺寸,使模型能捕獲更長距離的依賴信息。在此基礎上,添加高速神經網絡層形成CNNH 模型,模型結構如圖3 所示。

圖3 CNNH 模型結構
如圖3所示,CNNH模型前向傳播過程為:首先,使用訓練數據構建單詞表,并將代碼元素序列轉化為整數索引序列;其次,嵌入層將整數索引映射為低維稠密的嵌入向量,嵌入層并不使用Word2vec等預訓練詞嵌入,而是隨機初始化;再次,多尺度卷積層包含4 種卷積核尺寸的卷積層,每個卷積層后接全局最大池化操作,全局最大池化具有平衡不變性的特點,用于提取最重要的特征,通過池化還可以處理變長序列;最后,拼接層將多尺度卷積層提取的特征進行拼接,得到多尺度的代碼特征。
假設序列長度為n,經過嵌入層后序列可表示為:

式中:⊕為拼接操作。
假設xi:i+j為xi,xi+1,…,xi+j拼接后的張量,對其進行一維卷積操作產生新的特征,比如通過WC過濾器產生特征ci:

式中:C為非線性變換;WC為過濾器參數;b為偏置項。
將過濾器應用于整個序列產生特征圖(feature map)。

然后在特征圖上進行最大池化操作,作為該過濾器提取的特征:

假設使用k個過濾器,過濾器大小為5,得到最大池化后的特征圖:

使用多種過濾器大小來獲得不同尺度的代碼特征,進行拼接后得到特征,假設使用4 種大小的過濾器,分別為5,6,7,8,得到多尺度的代碼特征:

隨后使用高速神經網絡層特征進行組合、變換,高速神經網絡基于門機制引入變換門(transformer gate)和進位門(carry gate)對一部分特征進行處理,另一部分特征直接通過,可以讓網絡高效地進行特征學習,計算方式為:

式中:z為高速神經網絡層輸出;H為特征變換全連接層;T為變換門;C為進位門;WH為特征變換參數;WT為變換門參數;WC為進位門參數。
為了簡單,設置C=1-T,于是得到:

高速神經網絡根據變換門的輸出,輸出為0 的部分直接輸出到下一層,輸出為1 的部分進行變換后再輸出到下一層。
最后通過全連接層得到每個類別的概率。
本文利用顯著圖(Saliency map)對模型預測結果進行解釋,使模型具備一定的可解釋性。假定模型及其損失函數是可微分的,對每一個輸入嵌入向量可以得到其對應的梯度,使用每個嵌入向量的梯度,可以為每個輸入的代碼元素計算一個分數,該分數表示模型預測結果對嵌入向量變化的敏感程度,得分越高,表示模型對其越敏感,即重要性越高。本文使用Allennlp[12]提供的顯著圖模塊得到代碼元素的重要性分數。
本節對實驗使用的實驗環境、數據集及評價指標進行介紹,并與其他方法進行對比,驗證本文提出方法的有效性。
本文實驗使用的計算機配置:GPU 為GeForce 1080Ti,CPU 為Intel? Core ? i7-7700。操作系統為Linux Mint 20.3,內核為5.4.0-96-generic,開發語言為Python(Python 3.8),基于Allennlp 進行編碼,包括數據讀取和模型構建,GPU 加速環境為CUDA 10.3,相關依賴包為PyTorch 1.10,Allennlp 2.80。
采用Li 等人[3]從軟件保障參考數據集(Software Assurance Reference Dataset,SARD)、美國國家漏洞數據庫(National Vulnerability Database,NVD)等提取的SeVC 數據集對模型進行評估。數據集中每個代碼切片有0 或1 的標簽,1 代碼為漏洞樣本,0 代碼為非漏洞樣本。數據集的劃分與原文中同樣采取8 ∶2 作為訓練集和測試集的劃分比例,并使用該文獻使用的BLSTM 和BGRU 模型作為對比。數據集共包含4 個子數據集,分別為函數調用(API Function Call)、數組使用(Array Usage)、指針使用(Pointer Usage)和算術表達式(Arithmetic Expression)子數據集。本文首先針對每種類別的數據集分別使用單獨的模型進行訓練與測試,其次將所有數據合并使用模型進行訓練與測試。數據集信息如表1 所示。

表1 數據集樣本數目
本文采用的指標為分類模型中常用的指標,包括誤報率、漏報率、精確率、準確率、F1 分數、馬修斯相關系數(Matthews Correlation Coefficient,MCC)。判斷代碼片段是否包含漏洞為二分類問題,將漏洞樣本作為正樣本,將無漏洞樣本作為負樣本。誤報率表示負樣本被預測為正樣本的個數占總的負樣本的比例。漏報率為正樣本被預測為負樣本占總的正樣本的比例。準確率為預測正確的樣本占總量的比例,數據不均衡情況下不能準確評價模型的性能。精確率為預測為正樣本且預測正確的樣本數占預測為正樣本數的比例。召回率為預測為正且預測正確的樣本占實際所有正樣本數的比例,召回率與漏報率之和為1。F1 分數為精確率和召回率的加權平均。MCC[4]系數表示實際樣本與預測樣本之間的相關系數,值域為[-1,1],當值為1 時,代表模型完美預測;值為0 時,代表預測不比隨機預測好;值為-1 時,則代表預測與實際結果完全不一致,適用于評估類別不平衡下的模型性能。
參數設置主要包括模型配置參數與訓練配置參數兩個部分。
模型配置參數如表2 所示,其中最重要的參數為卷積核尺寸,包含4 種卷積核尺寸,4 種卷積核大小的卷積層提取代碼的N元語法特征。實驗表明,與自然語言文本相比,使用大尺寸卷積核在源代碼上的表現更好,大尺寸卷積核能捕獲較長的依賴關系。

表2 模型參數
訓練配置參數包括優化器、損失函數、學習率、權重衰減,參數如表3 所示。

表3 訓練參數
3.5.1 評價指標對比
本文與SySeVR 中的結果進行對比來驗證本文提出的CNNH 模型的有效性,如表4 為函數調用子數據集的實驗結果,表5 為算術表達式子數據集的實驗結果,表6 為數組使用子數據集的實驗結果,表7 為指針使用子數據集的實驗結果,表8 為整個數據集的實驗結果。其中CNN 代表僅含多尺度卷積神經網絡的模型,GRU 和LSTM 為循環神經網絡基線模型。

表4 函數調用數據集實驗結果 %

表5 算術表達式數據集實驗結果 %

表6 數組使用數據集實驗結果 %

表7 指針使用數據集實驗結果

表8 整體數據集實驗結果
本文使用的數據集存在樣本不均衡問題,準確率不能全面評估模型的性能,主要討論其他指標。在整體數據集中,CNNH 模型的各項指標均優于其他模型,相較文獻[3],漏報率降低11.6%,F1 分數和MCC 分別提升8.1%和8.8%。通過上述實驗可以看出使用多尺度卷積神經網絡的整體性能要好于循環神經網絡;CNNH 模型相較CNN 模型漏報率降低4.3%,精確率提升3.6%,F1 分數和MCC分別提升2.2%和2.5%,可以看出使用高速神經網絡層后,模型表現得到進一步提升。
如表9 所示,卷積循環神經網絡的訓練速度快于循環神經網絡,添加高速神經網絡后訓練時間又大幅減少,而且高速神經網絡基于門機制的殘差結構更容易訓練,同時使一部分輸入不經過變換直接通過網絡提升了模型的運行速度。

表9 訓練一個epoch 所需要的時間
3.5.2 顯著圖結果
圖4、圖5、圖6、圖7 分別為在函數調用數據樣本、算術表達式數據樣本、數組使用數據樣本和指針使用樣本的顯著圖結果示例。圖中顏色越深代表代碼元素的分數越高。

圖4 函數調用樣本示例
如圖4 所示,此函數調用樣本問題為if 判斷沒有考慮variable_0 為負數的情況,于是memcpy 時發生內存訪問錯誤,可以看出variable_0 與memcpy具有較高的分數。
如圖5 所示,此算術表達式樣本問題為variable_0 進行平方時可能會產生整數溢出問題,可以看出variable_0 和variable_4 有較高分數。

圖5 算術表達式樣本示例
如圖6 所示,此數組使用樣本問題為strcpy 沒有限制復制的長度,可能會產生非法的內存訪問,可以看出variable_0 有較高的分數。

圖6 數組使用樣本示例

圖7 指針使用樣本示例
如圖7 所示,此指針使用樣本問題為variable_1長度為50,而memmove 時長度為100,可以看出variable_1 有較高的分數。
通過以上樣本可以看出,使用顯著圖得到每個代碼元素的重要性分數不能準確反映漏洞成因與位置,但仍能得出對預測結果重要的一些代碼元素。顯著圖使模型具備一定的可解釋性,有助于審計人員人工審查與驗證。
3.5.3 結果分析
從實驗結果來看,卷積神經網絡模型整體性能優于循環神經網絡模型,誤報率、漏報率、準確率、F1 分數、MCC 系數等各種指標均有較大提升的同時,運行速度也有較大提升。CNNH 模型相對于CNN 模型性能有小幅度提升,同時運行速度也有提高,這是由于高速神經網絡利用門機制對一部分輸入進行處理,而另一部分輸入直接通過,從而提高了運行速度。
通過與其他方法的對比,本文提出的模型具有以下優勢:
(1)多尺度卷積神經網絡特征提取能有效提升漏洞檢測的各類指標,相較于循環神經網絡有較大提升,且運行速度大幅提升;
(2)高速神經網絡對特征進行變換,有利于模型學習抽象代碼特征,進一步提高模型的表現和運行速度;
(3)利用顯著圖,使模型具備一定的可解釋性,可輔助審計人員確認漏洞。
本文提出了一種基于卷積神經網絡的源代碼漏洞檢測模型。該模型使用切片后的代碼作為代碼表征提高訓練及學習效率;使用多尺度的卷積神經網絡提取代碼特征,相比循環神經網絡不僅漏報率大幅降低,訓練和預測速度也得到提升;使用高速神經網絡不僅能進一步提升模型性能,其門機制還進一步提升模型訓練和預測速度。實驗結果表明,本文提出的基于SeVC 代碼表征和卷積神經網絡及高速神經網絡的源代碼漏洞檢測模型,相比SySeVR可大幅降低漏報率,有效提升準確率、F1 分數、MCC 系數等指標。
本文提出的方法仍存在改進的空間:第一,本方法使用SeVC 作為代碼表征,SeVC 為平整的代碼序列,雖然包含代碼的數據依賴和控制信息,但SeVC 并不包含代碼的結構信息,未來嘗試加入代碼的結構信息,比如代碼的圖表征;第二,本方法對漏洞檢測作為二分類問題處理,只能預測是否有漏洞,并不能判斷漏洞類別,未來嘗試解決漏洞的多分類問題并對其進行解釋,實現更細粒度的源代碼漏洞檢測。