基于深度學(xué)習(xí)的源代碼缺陷檢測研究綜述
點(diǎn)擊下方卡片,關(guān)注“新機(jī)器視覺”公眾號
重磅干貨,第一時(shí)間送達(dá)
源自:軟件學(xué)報(bào) 作者:鄧梟 葉蔚 謝睿 張世琨
摘
要
源代碼缺陷檢測是判別程序代碼中是否存在非預(yù)期行為的過程, 廣泛應(yīng)用于軟件測試、軟件維護(hù)等軟件工程任務(wù), 對軟件的功能保障與應(yīng)用安全方面具有至關(guān)重要的作用. 傳統(tǒng)的缺陷檢測研究以程序分析為基礎(chǔ), 通常需要很強(qiáng)的領(lǐng)域知識與復(fù)雜的計(jì)算規(guī)則, 面臨狀態(tài)爆炸問題, 導(dǎo)致檢測性能有限, 在誤報(bào)漏報(bào)率上都有較大提高空間. 近年來, 開源社區(qū)的蓬勃發(fā)展積累了以開源代碼為核心的海量數(shù)據(jù), 在此背景下, 利用深度學(xué)習(xí)的特征學(xué)習(xí)能力能夠自動(dòng)學(xué)習(xí)語義豐富的代碼表示, 從而為缺陷檢測提供一種新的途徑. 搜集了該領(lǐng)域最新的高水平論文, 從缺陷代碼數(shù)據(jù)集與深度學(xué)習(xí)缺陷檢測模型兩方面系統(tǒng)地對當(dāng)前方法進(jìn)行了歸納與闡述. 最后對該領(lǐng)域研究所面臨的主要挑戰(zhàn)進(jìn)行總結(jié), 并展望了未來可能的研究重點(diǎn).
關(guān)鍵詞
深度學(xué)習(xí) 缺陷檢測 代碼表征
1 引言
隨著越來越多的行業(yè)使用軟件作為其業(yè)務(wù)載體, 代碼已經(jīng)成為支撐社會(huì)正常運(yùn)轉(zhuǎn)的最基本元素之一, 軟件的安全性問題也正在成為當(dāng)今社會(huì)的根本性和基礎(chǔ)性的問題. 軟件質(zhì)量已經(jīng)直接影響了人們的日常生活.美國國家標(biāo)準(zhǔn)與技術(shù)研究院的一項(xiàng)技術(shù)報(bào)告指出, 軟件缺陷每年對美國造成的經(jīng)濟(jì)損失高達(dá)600億美元[1].
然而, 由于傳統(tǒng)的缺陷檢測需要專業(yè)人員花費(fèi)較多的人力, 其在軟件開發(fā)過程中一直占用了較高的成本.實(shí)證研究表明, 缺陷檢測與修復(fù)耗費(fèi)成本占軟件開發(fā)所有成本的50%?70%[2]. 因此, 人們對自動(dòng)化缺陷檢測的需求日益增長.
隨著開源軟件的蓬勃發(fā)展, 研究者們能夠獲取的代碼量與缺陷信息越來越多. 成立于2008年的開源項(xiàng)目托管網(wǎng)站GitHub, 截至2020年, 已有超過5 000萬名用戶、1億個(gè)開源項(xiàng)目和2億的提交請求, 覆蓋了超過4.28億個(gè)文件. 截至2021年9月, 缺陷名錄網(wǎng)站NVD已經(jīng)收錄了171 178條缺陷數(shù)據(jù). 這些代碼數(shù)據(jù)為基于學(xué)習(xí)的缺陷檢測研究提供了充分的數(shù)據(jù)基礎(chǔ).
近年來, 大規(guī)模的數(shù)據(jù)和硬件方面不斷提升的計(jì)算能力, 使得深度學(xué)習(xí)技術(shù)在圖像處理、語音識別、自然語言處理等領(lǐng)域的多項(xiàng)任務(wù)上取得了突破性的進(jìn)展, 促成了人工智能的第三次浪潮. 于是, 研究者們也逐漸開始在代碼領(lǐng)域應(yīng)用深度學(xué)習(xí)來嘗試替代傳統(tǒng)的研究方法, 期望通過深度學(xué)習(xí)來解決現(xiàn)有方法無法解決的一些問題.
經(jīng)過近5年的探究, 深度學(xué)習(xí)對缺陷代碼特征挖掘的能力得到了一定的驗(yàn)證, 也吸引了越來越多的研究者從傳統(tǒng)缺陷檢測方法轉(zhuǎn)向使用深度學(xué)習(xí). 同時(shí), 深度學(xué)習(xí)方法應(yīng)用于源代碼缺陷檢測在數(shù)據(jù)集構(gòu)建和模型設(shè)計(jì)方面依然面臨眾多挑戰(zhàn). 本綜述即聚焦于基于深度學(xué)習(xí)的源代碼缺陷檢測技術(shù)研究.
1.1
術(shù)語定義
軟件源代碼安全作為軟件安全的重要研究點(diǎn), 其核心內(nèi)容是對軟件源代碼進(jìn)行缺陷檢測. 源代碼缺陷即程序代碼中存在的某種破壞正常運(yùn)行能力的問題、錯(cuò)誤或隱藏的功能缺陷, 會(huì)導(dǎo)致軟件產(chǎn)品在某種程度上不能滿足用戶的需要[3]. 源代碼漏洞是源代碼缺陷的一種, 可導(dǎo)致攻擊者利用的缺陷稱為漏洞[4]. 當(dāng)前很多研究特定于漏洞, 因此在總體概述中, 我們將兩者統(tǒng)稱為“缺陷”, 在特定上下文中會(huì)區(qū)分“缺陷”與“漏洞”.
1.2
傳統(tǒng)缺陷檢測技術(shù)概述
源代碼缺陷檢測是檢查并發(fā)現(xiàn)軟件系統(tǒng)中存在缺陷的主要手段之一, 也是成熟的工業(yè)軟件在開發(fā)過程中必不可少的一道工序. 其通過利用統(tǒng)計(jì)工具對軟件代碼進(jìn)行各維度度量上的審計(jì), 或利用分析工具分析軟件的執(zhí)行過程來查找并定位軟件的設(shè)計(jì)錯(cuò)誤、編碼缺陷、運(yùn)行故障. 從運(yùn)行模式上看, 早期的缺陷檢測技術(shù)可依據(jù)是否需要運(yùn)行待檢測程序劃分為靜態(tài)分析方法與動(dòng)態(tài)分析方法: 靜態(tài)分析方法一般應(yīng)用于軟件的開發(fā)編碼階段, 其無需運(yùn)行軟件, 而是通過掃描源代碼分析詞法、語法、控制流和數(shù)據(jù)流等信息來發(fā)現(xiàn)缺陷; 動(dòng)態(tài)分析方法則一般應(yīng)用于軟件的測試運(yùn)行階段, 在軟件程序運(yùn)行過程中, 通過分析動(dòng)態(tài)調(diào)試器中程序的狀態(tài)、執(zhí)行路徑等信息來發(fā)現(xiàn)缺陷. 在該領(lǐng)域幾十年的發(fā)展歷程中, 當(dāng)前已有許多公開的缺陷檢測工具, 如: Coverity[5]、Klocwork[6]以及Cobot[7]等典型的通用缺陷檢測工具, 通過對程序源代碼進(jìn)行靜態(tài)分析與規(guī)則判別來檢測系統(tǒng)缺陷; KLEE[8]、S2E[9]、Mayhem[10]等動(dòng)態(tài)工具采用符號執(zhí)行這種動(dòng)態(tài)分析方法進(jìn)行缺陷檢測; libFuzzer[11]、Radamsa[12]以及AFL[13]等動(dòng)態(tài)工具采用基于模糊測試的動(dòng)態(tài)分析方法排查錯(cuò)誤. 同時(shí), 也有相關(guān)研究嘗試通過動(dòng)靜態(tài)相結(jié)合的分析方法來提高檢測效率和準(zhǔn)確率. 如: angr[14]集成了靜態(tài)分析和動(dòng)態(tài)符號執(zhí)行, 能夠?qū)崿F(xiàn)自動(dòng)化分析二進(jìn)制文件; SAGE[15]結(jié)合使用了模糊測試和符號執(zhí)行, 并將動(dòng)態(tài)符號執(zhí)行應(yīng)用在x86架構(gòu)的程序分析中. 近年來, 為了提高缺陷檢測的效率, 也出現(xiàn)了一些自動(dòng)化或半自動(dòng)化的缺陷挖掘工具, 比較有代表性的如: Bochspwn[16]對內(nèi)核層采用污點(diǎn)追蹤, 從而檢測用戶層泄露數(shù)據(jù)的行為; Digtool[17]針對Windows系統(tǒng), 可自動(dòng)化捕獲程序執(zhí)行過程中觸發(fā)的缺陷; 谷歌團(tuán)隊(duì)推出的Syzkaller[18]針對Linux內(nèi)核進(jìn)行無監(jiān)督、覆蓋引導(dǎo)的模糊測試; RapidScan[19]缺陷掃描器則通過自動(dòng)化執(zhí)行nmap、dnsrecon和wafw00f等多個(gè)安全掃描工具, 通過多個(gè)工具掃描結(jié)果的融合共同發(fā)現(xiàn)缺陷.
盡管擁有較長的研究歷史, 傳統(tǒng)的缺陷檢測方法依然存在由其工作模式帶來的難以避免的不足. 如傳統(tǒng)的靜態(tài)分析方法往往依賴于專家人工構(gòu)造缺陷模式, 隨著軟件與缺陷復(fù)雜性的增加, 人工構(gòu)造成本和難度過高, 且人的主觀性導(dǎo)致不同專家對缺陷的理解不一, 這些都會(huì)嚴(yán)重影響誤報(bào)率和漏報(bào)率. 動(dòng)態(tài)分析方法中, 監(jiān)測目標(biāo)程序的崩潰是模糊測試發(fā)現(xiàn)漏洞的重要依據(jù)之一, 因此測試效果嚴(yán)重依賴于輸入種子的質(zhì)量, 而測試用例的自動(dòng)生成與變異存在較大的偶然性, 其存在測試冗余、測試攻擊面模糊、難以發(fā)現(xiàn)訪問控制漏洞和設(shè)計(jì)邏輯錯(cuò)誤等問題[20]. 動(dòng)態(tài)分析方法中的符號執(zhí)行方法雖然能以較少的測試用例覆蓋更多的程序路徑, 從而挖掘復(fù)雜軟件更深層次的缺陷, 但仍然存在路徑爆炸、約束求解難、內(nèi)存建模與并行處理復(fù)雜等問題[21], 單獨(dú)處理大型軟件系統(tǒng)時(shí)仍存在較大困難[22]. 因此, 雖然上述早期缺陷檢測方法已在各類小型規(guī)模軟件的缺陷檢測任務(wù)中取得了一定成果, 但在實(shí)際的代碼工業(yè)環(huán)境中應(yīng)對大型復(fù)雜軟件系統(tǒng)以及變化多樣的新型缺陷時(shí), 通常無法滿足需求.
1.3
基于傳統(tǒng)機(jī)器學(xué)習(xí)的缺陷檢測
針對大型復(fù)雜軟件系統(tǒng)的缺陷檢測問題, 研究者一方面嘗試通過優(yōu)化和改造現(xiàn)有方法來突破傳統(tǒng)缺陷檢測方法在檢測能力上的瓶頸, 另一方面嘗試探索新的智能化軟件缺陷檢測方法. 直觀上認(rèn)為, 大部分缺陷相關(guān)信息可以通過代碼分析得到, 即挖掘軟件缺陷的能力與分析代碼數(shù)據(jù)的能力緊密相關(guān), 而基于學(xué)習(xí)的方法非常適合于從海量數(shù)據(jù)中發(fā)現(xiàn)和學(xué)習(xí)規(guī)律. 理論研究中, Hindle等人[23]利用統(tǒng)計(jì)學(xué)的方法將編程語言和自然語言進(jìn)行比較, 研究結(jié)果表明, 兩者具有非常相似的統(tǒng)計(jì)學(xué)特性, 甚至編程語言更加規(guī)整, 從而提出了代碼的“自然說”假設(shè). 受到這個(gè)假設(shè)的啟發(fā), 研究人員逐漸意識到運(yùn)用統(tǒng)計(jì)學(xué)習(xí)方法對代碼中蘊(yùn)含的規(guī)律進(jìn)行分析和泛化的可行性.
早期基于學(xué)習(xí)的缺陷檢測研究主要使用機(jī)器學(xué)習(xí)方法, 如VCCFinder[24]針對數(shù)據(jù)形態(tài)設(shè)計(jì)人工特征并進(jìn)行統(tǒng)計(jì), 得到具有區(qū)分性的特征項(xiàng), 在對樣本特征值進(jìn)行One-Hot編碼后, 使用支持向量機(jī)對其進(jìn)行分類. 但該類方法在效率與效果上均存在較大的不足: 一方面, 大多數(shù)機(jī)器學(xué)習(xí)方法依然需要專家人工構(gòu)造特征作為輸入, 其檢測能力受限于特征工程的質(zhì)量高低; 另一方面, 當(dāng)前的機(jī)器學(xué)習(xí)方法在實(shí)際的檢測效果上存在較高的誤報(bào)率, 難以達(dá)到實(shí)際應(yīng)用的需求. 究其根本, 主要原因是機(jī)器學(xué)習(xí)模型對深層特征的挖掘能力有限.
1.4
基于深度學(xué)習(xí)的缺陷檢測
得益于深度神經(jīng)網(wǎng)絡(luò)在圖像識別、自然語言處理等任務(wù)上取得的巨大成功, 人們發(fā)現(xiàn), 深度學(xué)習(xí)方法在挖掘深層特征上更加具有優(yōu)勢. 一些研究者開始嘗試將其引入源代碼缺陷檢測任務(wù). 當(dāng)前的結(jié)果顯示, 深度學(xué)習(xí)在缺陷檢測任務(wù)上同樣具有傳統(tǒng)方法和機(jī)器學(xué)習(xí)方法無法比擬的優(yōu)勢. 并且, 由于其研究歷史相對短暫, 還有相當(dāng)深入的空間供研究者探究.
使用深度學(xué)習(xí)進(jìn)行缺陷檢測任務(wù), 核心構(gòu)成即為兩部分: 缺陷代碼數(shù)據(jù)集與深度學(xué)習(xí)缺陷檢測模型. 缺陷代碼數(shù)據(jù)集是深度學(xué)習(xí)模型的學(xué)習(xí)基礎(chǔ)與特征來源, 其需要擁有足夠規(guī)模的代碼數(shù)據(jù)來對缺陷代碼與非缺陷代碼進(jìn)行表征. 深度學(xué)習(xí)缺陷檢測模型則需要根據(jù)代碼的特性設(shè)置合適的網(wǎng)絡(luò)結(jié)構(gòu), 以充分挖掘缺陷代碼數(shù)據(jù)集中的特征, 從而得到區(qū)分缺陷代碼與非缺陷代碼的能力.
本文廣泛收集了當(dāng)前將深度學(xué)習(xí)應(yīng)用于源代碼缺陷檢測的相關(guān)研究. 我們使用“vulnerability/defect/bug”等關(guān)鍵詞查詢了谷歌學(xué)術(shù)搜索、IEEE Xplore、ACM Digital Library、Springer、DBLP、arXiv以及中國知網(wǎng)CNKI等搜索引擎和數(shù)據(jù)庫, 共查詢到908條結(jié)果; 隨后, 通過“code/detection”等關(guān)鍵詞篩查文章摘要, 保留了其中237篇; 再由2人逐一對查詢結(jié)果的標(biāo)題、摘要進(jìn)行人工審查, 過濾不使用深度學(xué)習(xí)方法的無關(guān)內(nèi)容, 在出現(xiàn)分歧時(shí)共同進(jìn)行二次討論; 最后根據(jù)文獻(xiàn)的引用情況進(jìn)行查缺補(bǔ)漏. 最終, 我們一共搜集到149篇基于深度學(xué)習(xí)進(jìn)行源代碼缺陷檢測的相關(guān)文章, 時(shí)間覆蓋2017年?2021年11月, 其詳細(xì)的年份分布情況如圖 1-1所示.

圖 1-1 不同年份論文發(fā)表分布
可以看到, 從2017年起, 深度學(xué)習(xí)開始被引入到源代碼缺陷檢測領(lǐng)域. 近年來, 該領(lǐng)域論文的發(fā)表數(shù)量呈逐年增加的趨勢. 該數(shù)據(jù)表明, 使用深度學(xué)習(xí)進(jìn)行缺陷檢測的研究熱度在不斷增加.
本文在介紹深度學(xué)習(xí)缺陷檢測技術(shù)時(shí)優(yōu)先選擇了CCF分級較高的論文, 包括CCF-B及以上和部分高質(zhì)量的CCF-C級論文. 最終, 本文選取了67篇深度學(xué)習(xí)源代碼缺陷檢測相關(guān)論文進(jìn)行詳細(xì)介紹, 其中相當(dāng)一部分論文來自所涉及領(lǐng)域的高質(zhì)量會(huì)議和期刊, 例如USENIX Security會(huì)議(4篇)、CCS會(huì)議(2篇)、OOPSLA會(huì)議(2篇)、NeurIPS會(huì)議(2篇)、IJCAI會(huì)議(2篇)、ESEC/FSE會(huì)議(1篇)、ACL會(huì)議(1篇)、ICML會(huì)議(1篇)、TDSC期刊(4篇)、TOSEM期刊(2篇)、TSE期刊(1篇)、Proc. IEEE期刊(1篇)、《軟件學(xué)報(bào)》(1篇)等.
1.5
相關(guān)綜述
事實(shí)上, 在2019年底, 李韻等人[25]就已經(jīng)對基于機(jī)器學(xué)習(xí)的軟件漏洞挖掘方法進(jìn)行了分類與分析, 其重點(diǎn)關(guān)注機(jī)器學(xué)習(xí)方法, 且主要關(guān)注2010?2019年的文獻(xiàn). 而該領(lǐng)域中基于深度學(xué)習(xí)的方法作為近年的熱門方向, 其相關(guān)文獻(xiàn)主要發(fā)表于2019?2021年間, 因此本綜述與前人總結(jié)在技術(shù)關(guān)注點(diǎn)與文獻(xiàn)分布上均有較大的差異, 可以作為前文的補(bǔ)充與進(jìn)一步的延申擴(kuò)展. 此外, 還有一些針對缺陷檢測技術(shù)的英文綜述, 如Chakraborty等人[26]和Lin等人[27]的研究, 與本文的方向相近. 但此類綜述往往只關(guān)注深度模型, 而本文在覆蓋更新研究點(diǎn)的同時(shí), 對數(shù)據(jù)集方面也進(jìn)行了更為細(xì)致的分析.
本文從源代碼缺陷數(shù)據(jù)集構(gòu)造與深度學(xué)習(xí)缺陷檢測模型這兩個(gè)技術(shù)模塊對當(dāng)前研究進(jìn)行了分類歸納與整理, 并對目前該研究領(lǐng)域亟待解決的問題與未來可能的研究方向進(jìn)行了闡述.
2 缺陷代碼數(shù)據(jù)集的構(gòu)造
由于使用深度學(xué)習(xí)進(jìn)行缺陷檢測的研究近幾年才興起, 因此有別于一些經(jīng)典、成熟的深度學(xué)習(xí)任務(wù)擁有統(tǒng)一、公認(rèn)的數(shù)據(jù)集, 當(dāng)前在缺陷檢測領(lǐng)域并沒有一個(gè)用來統(tǒng)一評測的缺陷代碼數(shù)據(jù)集. 當(dāng)前的研究往往是自行構(gòu)建一個(gè)缺陷代碼數(shù)據(jù)集, 作為衡量模型性能的數(shù)據(jù)基礎(chǔ). 這就導(dǎo)致各個(gè)研究使用不同的自建數(shù)據(jù)集. 然而, 在不同數(shù)據(jù)集上依靠數(shù)值指標(biāo)來橫向比較不同模型的優(yōu)劣是不現(xiàn)實(shí)的, 因此, 當(dāng)前該領(lǐng)域的研究往往會(huì)回避模型之間的比較問題. 不過目前為止, 還沒有研究針對性地指出數(shù)據(jù)集不統(tǒng)一帶來的問題. 同時(shí), 自建缺陷代碼數(shù)據(jù)集的構(gòu)建過程也存在較多的模糊或近似的問題, 甚至存在一些不合理的操作, 這些都會(huì)嚴(yán)重地影響模型在其上的訓(xùn)練表現(xiàn). 因此, 本文將數(shù)據(jù)集的構(gòu)造方法作為基于深度學(xué)習(xí)的缺陷檢測中一個(gè)重要的研究點(diǎn), 著重關(guān)注這一部分的研究現(xiàn)狀與存在的問題.
不同于圖像處理、自然語言處理等任務(wù)擁有成熟、通用的數(shù)據(jù)集, 使用深度學(xué)習(xí)進(jìn)行缺陷檢測面臨著巨大的數(shù)據(jù)集方面的問題. 究其根本, 主要有兩個(gè)核心難點(diǎn).
(1) 在已知的真實(shí)項(xiàng)目中, 有缺陷的代碼數(shù)量有限. 缺陷本身就是重要資源, 有些甚至是涉及到更高層安全的戰(zhàn)略資源. 當(dāng)前, 許多研究花費(fèi)了大量精力進(jìn)行標(biāo)注, 但是不會(huì)公開或者僅部分公開; 代碼開源且已被公開確認(rèn)收錄的缺陷數(shù)量少, 且對齊關(guān)系模糊. 例如NVD缺陷庫中的數(shù)據(jù), 至今已有17萬余條, 但經(jīng)過驗(yàn)證, 能夠?qū)R到具體代碼的只有5 300余條, 細(xì)分至不同程序語言則數(shù)量更加有限, 難以支撐深度模型的訓(xùn)練; 商業(yè)工具自行構(gòu)造并收集的測試數(shù)據(jù)集, 由于其巨大的商業(yè)價(jià)值不會(huì)輕易公開;
(2) 人工標(biāo)注或自動(dòng)化生成的難度和成本極高. 對于某些領(lǐng)域, 人工標(biāo)注數(shù)據(jù)的成本是容易的, 例如圖片、文本、語音, 大部分標(biāo)注任務(wù)普通人即可完成, 這就使得其標(biāo)注的成本相對低廉, 可以通過眾包的方式完成. 但是對于專業(yè)的程序員, 識別缺陷也是極其費(fèi)時(shí)耗力的工作.
因此, 缺陷代碼數(shù)據(jù)集作為深度學(xué)習(xí)缺陷檢測任務(wù)的基礎(chǔ), 具有很高的重要性, 但同時(shí)構(gòu)造難度較大.
2.1
缺陷代碼數(shù)據(jù)集的構(gòu)造方法分類
構(gòu)造缺陷代碼數(shù)據(jù)集, 從流程上可以分為3個(gè)主要技術(shù)環(huán)節(jié): 缺陷條目的獲取、缺陷代碼的抽取與處理、處理后樣本的標(biāo)注. 因此, 對應(yīng)每一個(gè)技術(shù)環(huán)節(jié), 我們按照數(shù)據(jù)來源、樣本粒度與標(biāo)簽來源對其進(jìn)行分類, 如圖 2-1所示.

圖 2-1 缺陷代碼數(shù)據(jù)集的構(gòu)造方法分類
構(gòu)造缺陷代碼數(shù)據(jù)集, 首先需要獲取缺陷數(shù)據(jù), 即找到與缺陷相關(guān)的代碼. 從數(shù)據(jù)來源上劃分, 當(dāng)前缺陷數(shù)據(jù)的來源主要分為4類: 人工構(gòu)造、缺陷庫抽取、代碼庫爬取與分析工具生成.
(1) 人工構(gòu)造即通過人工規(guī)則將正確代碼轉(zhuǎn)化為缺陷代碼;
(2) 缺陷庫抽取即以公開的缺陷數(shù)據(jù)庫為入口, 抽取指定的缺陷類型條目, 并提取對應(yīng)的缺陷代碼;
(3) 代碼庫爬取即直接檢索代碼倉庫, 從中爬取出具有缺陷特征的代碼提交;
(4) 分析工具生成即通過缺陷分析工具對源代碼進(jìn)行缺陷檢測, 將檢測結(jié)果作為其是否含有缺陷的標(biāo)簽.
當(dāng)確認(rèn)了代碼中包含缺陷后, 如何選擇合適的粒度成為關(guān)鍵問題. 粒度過大則可能帶來較多噪聲與冗余, 粒度過小則可能使得缺陷特征丟失. 同時(shí), 不同的粒度適用的網(wǎng)絡(luò)結(jié)構(gòu)也不同, 良好的粒度與網(wǎng)絡(luò)組合能夠使得模型更好地捕獲缺陷特征. 當(dāng)前主要的樣本粒度為文件級、函數(shù)級、切片級及其他類別.
(1) 文件級主要是將項(xiàng)目進(jìn)行文件級拆分構(gòu)成數(shù)據(jù)集;
(2) 函數(shù)級大多數(shù)先獲得文件數(shù)據(jù), 再將其按照函數(shù)劃分為單個(gè)樣本;
(3) 切片級需要對代碼進(jìn)行解析, 并根據(jù)設(shè)定規(guī)則進(jìn)行切片.
當(dāng)?shù)玫搅颂幚砗蟮臉颖竞? 需要對其進(jìn)行是否含有缺陷的標(biāo)注.
(1) 若缺陷樣本是通過人工規(guī)則生成的, 則在生成時(shí)即已擁有標(biāo)簽, 可以自動(dòng)完成標(biāo)注;
(2) 對于從缺陷庫中抽取的缺陷數(shù)據(jù), 若采用與數(shù)據(jù)源相同的缺陷粒度, 則往往可以直接獲得其標(biāo)簽, 可以自動(dòng)完成標(biāo)注;
(3) 若需要對缺陷進(jìn)行更細(xì)粒度的處理, 則需要研究者自行進(jìn)行細(xì)粒度的標(biāo)注工作. 當(dāng)前, 獲取標(biāo)簽的方式主要分為自動(dòng)標(biāo)注與人工標(biāo)注兩種.
為了便于介紹, 下面我們使用數(shù)據(jù)來源作為分類維度, 對當(dāng)前的數(shù)據(jù)集構(gòu)造方法進(jìn)行介紹.
2.1.1
基于人工構(gòu)造
在軟件開發(fā)過程中, 為了測試軟件的可靠性, 往往會(huì)人工撰寫一些測試樣例用于測試. 這些測試樣例因此成為了天然的缺陷樣本數(shù)據(jù).
Sard (software assurance reference dataset)[28]是美國國家標(biāo)準(zhǔn)與技術(shù)研究院發(fā)布的軟件防護(hù)參考數(shù)據(jù)集, 旨在為用戶、研究者與軟件安全工具開發(fā)人員提供已知的安全缺陷來對安全工具與方法進(jìn)行測試評估. 該數(shù)據(jù)集收集了來自工業(yè)生產(chǎn)、人工構(gòu)造與學(xué)生撰寫的測試用例, 涵蓋C/C++、Java等7種語言, 當(dāng)前, 該數(shù)據(jù)集共包含測試用例177 184條. Sard中的代碼按照Good (不含缺陷)、Bad (包含缺陷)與Mix (含有缺陷及補(bǔ)丁)進(jìn)行分類, 并對缺陷部分明確標(biāo)注了缺陷觸發(fā)位置. 雖然Sard數(shù)據(jù)集中的測試用例來源不盡相同, 但其均為人工撰寫用于測試的基礎(chǔ)樣例, 其缺陷流程較為簡單, 復(fù)雜度較低, 與真實(shí)的代碼缺陷存在一定差距.
OWASP Benchmark[29]項(xiàng)目是一個(gè)綜合的Java測試樣例集, 專為軟件漏洞分析工具的自動(dòng)評估而設(shè)計(jì). 當(dāng)前, OWASP Benchmark測試套件有兩個(gè)主要版本(V1.1和V1.2), 包含11個(gè)類別的Web應(yīng)用程序漏洞的數(shù)千個(gè)標(biāo)記測試用例. 其中, V1.1中擁有更多的測試用例, 但用例不可執(zhí)行也不可利用, 且正負(fù)樣本不平衡. V1.2對這些問題進(jìn)行了改進(jìn), 其用例全部可執(zhí)行、可利用, 且正負(fù)樣本均衡.
在研究初期, 為了盡快獲得缺陷數(shù)據(jù), 很多缺陷代碼數(shù)據(jù)集是從缺陷庫中直接抽取出來的.
Xu等人[30]直接使用Sard數(shù)據(jù)集提供的數(shù)據(jù), 其選擇了其中緩沖區(qū)錯(cuò)誤(buffer error, CWE-119)與資源管理錯(cuò)誤(resource management error, CWE-399)這兩個(gè)類型, 共計(jì)23 185個(gè)程序, 其中, 11 093為缺陷程序, 占比47.8%.
Duan等人[31]也使用Sard數(shù)據(jù)集進(jìn)行測試, 他們?yōu)榱颂骄咳绾胃玫夭蹲饺毕荽a與非缺陷代碼中的細(xì)小差距, 因此Sard數(shù)據(jù)集正好可以滿足該需求. 最終, 他們選擇了緩沖區(qū)錯(cuò)誤(CWE-119)和資源管理(CWE- 399)這兩個(gè)類型, 按照函數(shù)級進(jìn)行收集, 共計(jì)28 049個(gè)函數(shù), 其中, 缺陷函數(shù)為10 561個(gè), 占比37.7%. 該數(shù)據(jù)集未開源.
Cao等人[32]使用了Sard數(shù)據(jù)集作為數(shù)據(jù)來源, 并同樣選取了其中CWE-399和CWE-119這兩類共計(jì)11 397個(gè)文件, 并按照函數(shù)進(jìn)行分割與打標(biāo). 最終, 該數(shù)據(jù)集包含63 828個(gè)函數(shù), 其中, 缺陷函數(shù)為46 337個(gè), 占比72.6%.
Saccente等人[33]在Sard的基礎(chǔ)上構(gòu)建了一個(gè)Java語言的函數(shù)級缺陷代碼數(shù)據(jù)集. 其首先選取了原數(shù)據(jù)集中類型下數(shù)量超過100的29個(gè)CWE缺陷類型, 共44 495個(gè)文件. 在預(yù)處理過程中, 其將對應(yīng)文件按函數(shù)級分割, 然后使用分詞器Javalang進(jìn)行分詞, 以作為向量形式投入模型. 該數(shù)據(jù)集已開源(https://gitlab.com/TUSoftwareEngineering/vulnerabilitylocalization-using-machine-learning).
Feng等人[34]從Sard中提取了3個(gè)級別的針對C/C++語言的函數(shù)級缺陷代碼數(shù)據(jù)集. 其中, 針對Buffer Overflow的BO數(shù)據(jù)集包括CWE-121與CWE-122, 用于測試模型對最常見的單一類型缺陷的檢測能力; 針對多個(gè)類型的5K數(shù)據(jù)集包括樣本數(shù)量大于5 000的全部類型; 最后是整個(gè)Sard數(shù)據(jù)集用于完整的評估模型. 所有的數(shù)據(jù)均按照函數(shù)進(jìn)行分割, 最終的完整數(shù)據(jù)集包含269 985個(gè)函數(shù), 其中, 缺陷函數(shù)為89 071個(gè), 占比33%. 該數(shù)據(jù)集未開源.
為了滿足圖神經(jīng)網(wǎng)絡(luò)的輸入需求, Ghaffarian等人[35]構(gòu)建了一個(gè)由多種代碼圖組成的缺陷代碼數(shù)據(jù)集. 該數(shù)據(jù)集基于Java語言, 其從OWASP Benchmark v1.2中提取了7個(gè)類型的測試樣例共1 698條, 其中, 缺陷樣例為932條, 占比54.9%. 該數(shù)據(jù)集并未開源. 但作者開源了其跨平臺代碼解析工具PROGEX[36], 其用于標(biāo)準(zhǔn)化地對程序生成各種圖表示, 以便與后續(xù)的模型作快速的數(shù)據(jù)準(zhǔn)備. 同時(shí), 該工具還支持將各種生成圖以不同的文本格式存儲(chǔ), 例如DOT、JSON、GML等.
雖然從測試樣例中抽取樣本較為快捷, 但其數(shù)量畢竟有限, 無法提供更大規(guī)模的缺陷樣本. 為此, 一些研究者嘗試自行構(gòu)造缺陷樣本, 其通過自行設(shè)定的規(guī)則, 對正確代碼變異來得到缺陷代碼.
為了利用代碼中變量與函數(shù)命名上的自然語言信息, Pradel等人[37]構(gòu)建了一個(gè)基于命名的缺陷數(shù)據(jù)集. 針對構(gòu)造數(shù)據(jù)集時(shí)存在的諸多困難, 他們選擇使用代碼轉(zhuǎn)換的方式, 將非缺陷代碼改寫為缺陷代碼, 從而極大地減少了構(gòu)造數(shù)據(jù)集所需的人力與計(jì)算資源. 具體來說, 其使用3種變異規(guī)則對代碼進(jìn)行修改, 包括交換函數(shù)參數(shù)、修改二元操作符、修改二元運(yùn)算中的操作數(shù). 這些操作都是在AST的基礎(chǔ)上進(jìn)行的. 由于其默認(rèn)大部分的代碼均為正確代碼(指的是不包含上述3種錯(cuò)誤模式), 因此轉(zhuǎn)化前的代碼即為非缺陷代碼, 轉(zhuǎn)化后的即為缺陷代碼. DeepBugs的數(shù)據(jù)集由150 000個(gè)JavaScript文件生成, 這些文件均由開源工程收集并經(jīng)過了清洗與去重, 一共包含6 860行代碼. 在經(jīng)過上述變異操作后, 最終該數(shù)據(jù)集包含16 634 458個(gè)樣本. 該數(shù)據(jù)集已開源(https://github.com/michaelpradel/DeepBugs).
Allamanis等人[38]同樣采用了人工規(guī)則自動(dòng)構(gòu)造缺陷數(shù)據(jù)的方法. 其在DeepBug[37]規(guī)則的基礎(chǔ)上, 增加了變量替換與常數(shù)替換兩種構(gòu)造規(guī)則. 其通過這一方法對PyPI中下載量前4 000名的Python項(xiàng)目進(jìn)行了變換, 構(gòu)造了針對Python語言的缺陷代碼數(shù)據(jù)集. 該數(shù)據(jù)集已開源(https://www.microsoft.com/en-us/download/103554).
Choi等人[39]選擇直接生成缺陷代碼段, 其自行構(gòu)建了一個(gè)針對緩沖區(qū)溢出類型的函數(shù)級C語言缺陷代碼數(shù)據(jù)集. 代碼生成規(guī)則中采用與Sard相同的緩沖區(qū)訪問函數(shù)和初始化方法, 以保持至少相同級別的任務(wù)復(fù)雜性. 該數(shù)據(jù)集中每個(gè)構(gòu)造的樣本代碼段均為一個(gè)無返回值函數(shù), 其由3個(gè)階段構(gòu)成: 初始化變量、緩沖區(qū)分配和緩沖區(qū)訪問. 在緩沖區(qū)的使用上, 分為直接調(diào)用、使用API調(diào)用、利用變量分配和利用API調(diào)用與變量重劃分共4個(gè)不同難度級別. 該數(shù)據(jù)集最終包含10 000個(gè)樣本, 其中, 缺陷樣本占比50.1%. 不過, 該數(shù)據(jù)集中的樣本構(gòu)造規(guī)則與邏輯較為簡單: 其長度均限定在8?30行, 遠(yuǎn)低于實(shí)際應(yīng)用場景中的待測函數(shù)代碼長度; 其對緩沖區(qū)的調(diào)用限定為4種模式, 均較為直接, 在程序復(fù)雜度上遠(yuǎn)低于實(shí)際應(yīng)用場景. 該數(shù)據(jù)集已開源(https://github.com/mjc92/buffer_overrun_memory_networks).
總的來說, 基于人工構(gòu)造的方法通過特定的規(guī)則可以快速地生成大量的樣本. 然而, 由此構(gòu)建的缺陷代碼數(shù)據(jù)集只能表征構(gòu)造規(guī)則, 這會(huì)導(dǎo)致訓(xùn)練出的深度模型只局限于對特定規(guī)則的識別, 而偏離其“缺陷檢測”的原始目標(biāo). 因此, 當(dāng)前通用類型檢測的系統(tǒng)不再人工構(gòu)造缺陷數(shù)據(jù)樣本.
2.1.2
基于缺陷庫抽取
當(dāng)前, 有一些機(jī)構(gòu)或組織對軟件開發(fā)中發(fā)現(xiàn)的缺陷進(jìn)行了收集、整理與發(fā)布, 因此通過該類缺陷庫即可獲得缺陷條目入口. 但是該類缺陷庫大多只有部分條目能夠鏈接到缺陷對應(yīng)的源代碼, 因此基于缺陷庫抽取缺陷數(shù)據(jù)的方法大多需要先篩選出其中對齊源代碼成功的條目, 再進(jìn)行后續(xù)的處理.
NVD (national vulnerability database)[40]是美國國土安全部下屬的聯(lián)邦計(jì)算機(jī)應(yīng)急準(zhǔn)備小組維護(hù)的國家漏洞數(shù)據(jù)庫, 是當(dāng)前較為權(quán)威的源代碼漏洞數(shù)據(jù)庫. 該庫實(shí)時(shí)同步CVE發(fā)布的條目, 在CVE基礎(chǔ)上提供安全評分、缺陷影響評級、修復(fù)信息、缺陷查找等功能, 并通過人工審核的方式將缺陷與原項(xiàng)目相關(guān)信息進(jìn)行鏈接.由于其數(shù)據(jù)相對較為齊全, 人工對齊源碼出處的質(zhì)量相對較高, 因此該缺陷庫成為當(dāng)前最常用的缺陷抽取源.
Lin等人[41]使用函數(shù)作為缺陷代碼的粒度, 其選擇了6個(gè)知名工程(LibTIFF、LibPNG、FFmpeg、Pidgin、VLC Media Player、Asterisk), 通過NVD檢索其相關(guān)缺陷, 并人工定位缺陷所在函數(shù), 剩余未被標(biāo)記為缺陷函數(shù)的即作為非缺陷函數(shù)加入數(shù)據(jù)集. 最終, 該數(shù)據(jù)集包含32 988個(gè)函數(shù), 其中, 缺陷函數(shù)為457個(gè), 占比1.4%, 不平衡的情況較嚴(yán)重. 該數(shù)據(jù)集已開源(https://github.com/DanielLin1986/TransferRepresentationLearning).
Li等人[42]提出了基于C/C++語言的切片級缺陷代碼數(shù)據(jù)集. 其檢索了NVD與Sard中緩沖區(qū)錯(cuò)誤(CWE-119)與資源管理錯(cuò)誤(CWE-399)這兩類缺陷條目, 選擇其中19個(gè)開源C/C++項(xiàng)目的相關(guān)缺陷. 其定義了代碼片段(code gadgets), 即語義上相互關(guān)聯(lián)的幾行代碼, 并用它來表示程序, 以使其避免函數(shù)級表示會(huì)帶來的無關(guān)噪聲信息. 其首先在源代碼中按照分析工具Checkmarx的危險(xiǎn)函數(shù)標(biāo)準(zhǔn)查找?guī)旌瘮?shù)與API函數(shù)調(diào)用作為危險(xiǎn)入口, 將其語句中的變量作為起點(diǎn)進(jìn)行切片, 并按照自然代碼順序進(jìn)行組合形成code gadget. 該切片只考慮數(shù)據(jù)依賴關(guān)系. 在標(biāo)注是否含有缺陷時(shí), 其依靠代碼片段中是否含有修復(fù)時(shí)被刪除或修改的語句來進(jìn)行判斷: 若有, 則標(biāo)注為缺陷片段. 最終, 該數(shù)據(jù)集包含61 638個(gè)代碼片段, 其中, 17 725個(gè)為缺陷片段, 占比28.8%. 不過, 其中僅有1.4% (840個(gè))來自于真實(shí)項(xiàng)目缺陷(NVD). 該數(shù)據(jù)集已開源(https://github.com/CGCL-codes/VulDeePecker).
為了支持多分類缺陷檢測任務(wù), Zou等人[43]在VulDeePecker[42]數(shù)據(jù)集上進(jìn)行了擴(kuò)充, 增加了控制依賴作為切片依據(jù), 并將缺陷類型也加入其中, 而不僅僅記錄其是否含有缺陷. 其μVulDeePecker數(shù)據(jù)集在切片時(shí)同時(shí)進(jìn)行前后向的切片, 并同時(shí)考慮數(shù)據(jù)依賴與控制依賴. 該數(shù)據(jù)集最終包含181 641個(gè)代碼片段, 其中, 43 119個(gè)為缺陷片段, 占比23.7%. 其共涉及40個(gè)CWE三級分類. 但是, 該數(shù)據(jù)集的缺陷樣本存在類型信息, 而非缺陷樣本均標(biāo)記為非缺陷類型, 不存在類型信息, 可能會(huì)影響模型的判斷. 并且, 該數(shù)據(jù)集中來自NVD的真實(shí)缺陷占比不到1%. 該數(shù)據(jù)集已開源(https://github.com/muVulDeePecker/muVulDeePecker).
由于VulDeePecker[42]數(shù)據(jù)集只考慮了以危險(xiǎn)庫/API函數(shù)調(diào)用作為入口的缺陷條目作為樣本, 因此只能提供兩種缺陷類型的樣本, 其覆蓋范圍較窄. Li等人[44]在其基礎(chǔ)上進(jìn)行了改進(jìn), 使其同時(shí)兼顧語法特征與語義特征, 從而更全面地表征缺陷以覆蓋更多的缺陷類型. 該數(shù)據(jù)集SySeVR同樣從NVD與Sard數(shù)據(jù)庫中抽取缺陷, 其首先根據(jù)Checkmarx的危險(xiǎn)變量規(guī)則提出了4種危險(xiǎn)入口(庫/API函數(shù)調(diào)用、數(shù)組使用、指針使用、算數(shù)表達(dá)式), 從代碼中的危險(xiǎn)入口開始切片. 與VulDeePecker數(shù)據(jù)集根據(jù)語句中的標(biāo)識符進(jìn)行切片不同的是, SySeVR數(shù)據(jù)集是在語句的程序依賴圖基礎(chǔ)上進(jìn)行切片, 從而利用控制依賴與數(shù)據(jù)依賴信息完善缺陷特征. SySeVR的標(biāo)簽方法與VulDeePecker數(shù)據(jù)集相同. 最終, SySeVR數(shù)據(jù)集包含420 627個(gè)代碼片段, 其中, 缺陷片段為56 395個(gè), 占比13.4%. 該數(shù)據(jù)集已開源(https://github.com/SySeVR/SySeVR).
缺陷代碼與其修復(fù)版本同時(shí)在數(shù)據(jù)集中可以幫助模型更好地學(xué)習(xí)到其中的差異, 并且能夠保證數(shù)據(jù)集正負(fù)樣本的平衡. 為此, Xiao等人[45]構(gòu)建了一個(gè)針對C/C++的缺陷代碼與修復(fù)數(shù)據(jù)集. 其選定了10個(gè)不同領(lǐng)域的開源工程, 從NVD和項(xiàng)目代碼提交中檢索相關(guān)缺陷與修復(fù), 根據(jù)修復(fù)的位置確定缺陷函數(shù). 該數(shù)據(jù)集只包含修復(fù)在單個(gè)函數(shù)內(nèi)部的. 最終, 該數(shù)據(jù)集包含25 377對缺陷與其修復(fù). 不過, 該數(shù)據(jù)集未開源.
Nikitopoulos等人[46]構(gòu)建了一個(gè)多語言的缺陷代碼數(shù)據(jù)集CrossVul. 其人工審查了NVD提及的5 877個(gè)Github提交, 確認(rèn)其鏈接的可用性, 并標(biāo)記了缺陷及其對應(yīng)補(bǔ)丁所在文件, 并將提交信息也作為數(shù)據(jù)一同保存. 該數(shù)據(jù)集最終涉及1 675個(gè)項(xiàng)目, 包括27 476個(gè)文件(缺陷與非缺陷各半), 涵蓋40種編程語言, 涉及168個(gè)CWE類型, 每一條缺陷都記錄了其對應(yīng)的CVE ID與其來源鏈接. 不過, 該數(shù)據(jù)集只是文件級數(shù)據(jù), 并沒有進(jìn)一步細(xì)化到函數(shù)甚至切片, 因此, 在缺陷檢測任務(wù)中使用可能需要較大工作量的細(xì)化標(biāo)注工作. 該數(shù)據(jù)集已開源(https://doi.org/10.5281/zenodo.4734050).
Lin等人[47]提出了一個(gè)針對深度學(xué)習(xí)缺陷函數(shù)檢測的C語言評測集. 其根據(jù)NVD與CVE的描述信息, 通過人工的方式將其對齊到GitHub代碼庫, 并標(biāo)注缺陷函數(shù)與缺陷文件. 其默認(rèn)最新版本的工程中其他文件均為非缺陷文件, 因此將新版本中未被標(biāo)記的文件和其中函數(shù)作為非缺陷樣本. 其標(biāo)注了9個(gè)開源工程, 共計(jì)5 780個(gè)文件60 768個(gè)函數(shù), 其中, 缺陷函數(shù)為1 471個(gè), 占比2.4%. 但是, 該數(shù)據(jù)集沒有考慮到缺陷類型等信息.
為了測試跨域?qū)W習(xí)方法的效果, Liu等人[48]提出了一個(gè)針對C/C++的缺陷代碼數(shù)據(jù)集. 其選用了VulDeePecker數(shù)據(jù)集中的CWE-119與CWE-399這兩類, 用來測試缺陷類型間的跨域. 其另外根據(jù)NVD與CVE信息人工標(biāo)注了3個(gè)開源項(xiàng)目(LibTIFF、FFmpeg、LibPNG)的函數(shù)級缺陷數(shù)據(jù), 每個(gè)項(xiàng)目均抽取了9種缺陷類型, 用來測試項(xiàng)目間的跨域. 非缺陷樣本都是從項(xiàng)目中未被標(biāo)記為缺陷樣本的函數(shù)中抽取的. 該數(shù)據(jù)集已開源(https://github.com/wolong3385/SVD-Source).
很多缺陷代碼數(shù)據(jù)集在構(gòu)造時(shí)都基于一個(gè)假設(shè): 工程代碼除了已知的缺陷以外沒有其他缺陷. 因此, 設(shè)計(jì)者將被標(biāo)記為缺陷樣本以外的部分當(dāng)作非缺陷樣本對待. 然而事實(shí)是, 新缺陷都是從這些“非缺陷樣本”中發(fā)現(xiàn)的. 因此, 這種假設(shè)會(huì)帶來許多噪聲從而影響模型的判別能力.
為此, Jimenez等人[49]放棄了缺陷樣本以外的代碼來避免這個(gè)問題, 他們只使用缺陷樣本和其對應(yīng)的修改后版本作為樣本來構(gòu)造數(shù)據(jù)集. 他們提出了一個(gè)自動(dòng)的可擴(kuò)展框架, 并由此構(gòu)建了缺陷代碼數(shù)據(jù)集VulData7. 其通過NVD作為缺陷入口, 選取4個(gè)C語言開源項(xiàng)目(Linux Kernel、Wireshark、OpenSSL、SystemD)的條目, 自動(dòng)將其對齊到項(xiàng)目代碼庫及相應(yīng)提交. VulData7記錄了每條缺陷的報(bào)告信息(描述、CVE編號、CWE編號、CVSS嚴(yán)重程度)、影響版本列表、修復(fù)提交和修復(fù)前后文件. 當(dāng)前版本的VulData7包含2 809條缺陷, 其中, 1 598條附帶了修復(fù)信息. 其更新機(jī)制會(huì)不斷同步NVD以不斷維護(hù)數(shù)據(jù)集. 該數(shù)據(jù)集已開源(https://github.com/electricalwind/data7).
Clemente等人[50]從缺陷跟蹤網(wǎng)站Bugzilla、Mozilla Foundation Security Advisory (MFSA)和Computer Vulnerability Exposure site (CVE)上提取信息構(gòu)建缺陷數(shù)據(jù)集. 其將搜索范圍限定在Mozilla的C++項(xiàng)目Firefox上, 根據(jù)網(wǎng)站的報(bào)出提取出缺陷相關(guān)文件. 最終, 該數(shù)據(jù)集包含395個(gè)文件, 其中有200個(gè)缺陷樣本, 占比50.6%. 該數(shù)據(jù)集未開源.
除了著名的通用缺陷庫以外, 許多大型軟件開發(fā)商都會(huì)安排安全團(tuán)隊(duì)自行維護(hù)其軟件產(chǎn)品的安全記錄, 這些安全記錄也可以為構(gòu)建缺陷代碼數(shù)據(jù)集提供可靠的信息.
Alexopoulos等人[51]提出了一種自動(dòng)構(gòu)建缺陷數(shù)據(jù)集的方法. 他們從Debian安全團(tuán)隊(duì)維護(hù)的缺陷庫Debian Security Advisories (DSAs)中進(jìn)行信息挖掘. 首先, 從DSA的缺陷報(bào)告中可以直接提取出報(bào)出的缺陷與對應(yīng)的NVD鏈接, 同時(shí)還包括其CWE缺陷類型與嚴(yán)重等級; 隨后, 使用官方提供的快照功能下載每個(gè)月的工程源代碼; 再通過開源工具PKGDIFF對相鄰版本的修改信息進(jìn)行生成, 從而定位出缺陷報(bào)告是在何時(shí)被引入. 該數(shù)據(jù)集最終選用了7個(gè)Debian項(xiàng)目, 分別是Linux kernel、Firefox、Chromium、PHP、OpenJDK、Thunderbird和Wireshark. 不過, 由于該研究還未完全完成, 該數(shù)據(jù)集未開源.
Fan等人[52]提出了一個(gè)針對C/C++語言的函數(shù)級缺陷代碼數(shù)據(jù)集Big-Vul. 其通過爬取CVE數(shù)據(jù)庫和相關(guān)源代碼倉庫中的GitHub鏈接, 定位了348個(gè)GitHub項(xiàng)目, 并對齊到每個(gè)缺陷的修復(fù)提交. 其將函數(shù)在修復(fù)前后兩個(gè)版本與CVE描述信息一并保存, 記錄了包括CVE ID、嚴(yán)重程度、描述等21個(gè)特征值. 項(xiàng)目中的其他非缺陷相關(guān)函數(shù)作為正確函數(shù)也加以保留. 最終, Big-Vul數(shù)據(jù)集包含3 754個(gè)代碼缺陷, 覆蓋91個(gè)缺陷類型, 共含有11 823個(gè)缺陷函數(shù)與253 096個(gè)非缺陷函數(shù), 缺陷函數(shù)占比4.5%. 該數(shù)據(jù)集已開源(https://github.com/ZeoVan/MSR_20_Code_Vulnerability_CSV_Dataset).
Li等人[53]從tera-PROMISE缺陷數(shù)據(jù)庫中抽取針對Java語言的文件級缺陷代碼數(shù)據(jù)集. 其選擇了7個(gè)開源Java項(xiàng)目包含的缺陷條目, 每個(gè)項(xiàng)目都選擇了連續(xù)的兩個(gè)版本. 從其對應(yīng)的GitHub倉庫中爬取了源文件, 并按照報(bào)出缺陷位置對文件進(jìn)行標(biāo)注. 最終, 該數(shù)據(jù)集包含3 290個(gè)文件, 其中, 缺陷文件為1 152個(gè), 占比35%. 該數(shù)據(jù)集未開源.
Zhang等人[54]同樣從tera-PROMISE數(shù)據(jù)集中抽取缺陷數(shù)據(jù), 其選擇了12個(gè)Java語言的開源項(xiàng)目, 共計(jì)5 194個(gè)文件, 其中, 缺陷文件為1 617個(gè), 占比31.1%. 該數(shù)據(jù)集同時(shí)還包含了20種傳統(tǒng)代碼度量信息.
Ponta等人[55]將NVD和50余個(gè)項(xiàng)目自身的安全記錄網(wǎng)站作為缺陷條目入口, 在4年的時(shí)間內(nèi)監(jiān)控其安全報(bào)告的情況, 通過人工的方式記錄缺陷相關(guān)提交(commit)與修復(fù)相關(guān)提交. 截至2019年, 該數(shù)據(jù)集共記錄了624個(gè)缺陷的修復(fù), 涉及1 282個(gè)提交, 跨越205個(gè)Java項(xiàng)目. 該數(shù)據(jù)集已開源(https://github.com/SAP/vulnerability-assessment-kb/tree/master/MSR2019).
當(dāng)前, 從NVD等缺陷庫中抽取缺陷條目已成為較為通用的做法, 其已經(jīng)成為構(gòu)建缺陷代碼數(shù)據(jù)集的重要數(shù)據(jù)來源. 這就意味著源缺陷庫的質(zhì)量會(huì)極大地影響所構(gòu)建數(shù)據(jù)集的質(zhì)量. 事實(shí)上, 通過細(xì)致的比對, 人們逐漸注意到該類缺陷庫的信息質(zhì)量存在一些問題. 例如, 在多個(gè)缺陷來源的對比中(如NVD與CVE)會(huì)出現(xiàn)缺陷信息不一致的情況. 如果對缺陷庫中的條目不加驗(yàn)證即作為標(biāo)答(當(dāng)今普遍做法), 會(huì)給缺陷數(shù)據(jù)集的構(gòu)建帶來噪聲, 繼而極大地影響在此基礎(chǔ)上訓(xùn)練的深度學(xué)習(xí)模型的檢測性能. 為此, Dong等人[56]提出了一個(gè)自動(dòng)化系統(tǒng)VIEM來檢測完全標(biāo)準(zhǔn)化的NVD數(shù)據(jù)庫與非結(jié)構(gòu)化CVE描述及其引用的漏洞報(bào)告之間的不一致信息.其使用了自然語言處理任務(wù)中的命名實(shí)體識別與關(guān)系抽取技術(shù), 對非結(jié)構(gòu)化信息進(jìn)行提取并與結(jié)構(gòu)化信息比較, 從而大規(guī)模地自動(dòng)檢測不一致信息. 其對過去20年中78 296個(gè)CVE ID與70 569條缺陷報(bào)告進(jìn)行了比對, 只有59.82%的條目可以嚴(yán)格匹配.
然而, 該不一致性的鑒別只針對缺陷影響的項(xiàng)目版本不一致性. 事實(shí)上, 由于公開缺陷庫都是由人工的方式進(jìn)行維護(hù), 其許多信息都可能存在錯(cuò)誤/不一致, 例如對應(yīng)的原提交鏈接等. 這些都會(huì)給以此為基礎(chǔ)構(gòu)造的缺陷代碼數(shù)據(jù)集帶來影響, 也需要進(jìn)行正確性的確認(rèn).
除了數(shù)據(jù)的沖突, 另一種影響數(shù)據(jù)集數(shù)量的問題是數(shù)據(jù)的缺失. 當(dāng)前, 由于需要大量的缺陷代碼數(shù)據(jù), 使用混合數(shù)據(jù)來源已成為一種常用的擴(kuò)增數(shù)據(jù)集的做法. 但是, 混合數(shù)據(jù)來源容易帶來的問題是屬性值的不全, 這是由各個(gè)缺陷庫的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)所導(dǎo)致的. 即使是同一數(shù)據(jù)源的缺陷數(shù)據(jù), 也可能有數(shù)據(jù)不全的情況. 例如, 在NVD缺陷庫中, 有些條目沒有CVE缺陷類型. 這種數(shù)據(jù)的缺失會(huì)影響數(shù)據(jù)集的數(shù)量與質(zhì)量, 需要對其進(jìn)行補(bǔ)全.
Rostami等人[57]針對缺陷代碼數(shù)據(jù)中數(shù)據(jù)缺失的問題設(shè)計(jì)了一個(gè)機(jī)器學(xué)習(xí)框架, 從數(shù)據(jù)完整的條目中學(xué)習(xí), 從而對缺失項(xiàng)進(jìn)行預(yù)測. 該方法能夠較好地預(yù)測缺失的類型數(shù)據(jù), 但對于無類型數(shù)據(jù), 該框架無法補(bǔ)全.
Gonzalez等人[58]同樣針對NVD數(shù)據(jù)集中分類信息補(bǔ)全標(biāo)注的問題, 提出了一個(gè)自動(dòng)缺陷標(biāo)注的方法. 其僅僅使用缺陷條目的CVE描述作為依據(jù), 在對描述信息進(jìn)行清洗并使用TF-IDF表示后, 使用6種分類器(樸素貝葉斯、決策樹、支持向量機(jī)、隨機(jī)森林、AdaBoost支持向量機(jī)、多數(shù)投票), 按照NVD漏洞描述規(guī)則(vulnerability description ontology)中的19個(gè)類型標(biāo)準(zhǔn)來對其進(jìn)行分類. 實(shí)驗(yàn)結(jié)果顯示: 多數(shù)投票的分類效果最佳, 準(zhǔn)確率達(dá)到74.5%. 但考慮到訓(xùn)練成本和時(shí)間, 使用支持向量機(jī)是該任務(wù)的最優(yōu)選擇. 不過, 該方法同樣無法對選擇型數(shù)據(jù)進(jìn)行補(bǔ)全.
因此, 對于非選擇型數(shù)據(jù)的缺失, 如何對其加以補(bǔ)全而不是簡單丟棄, 是構(gòu)造一個(gè)樣本數(shù)量足夠多的數(shù)據(jù)集的可行方向, 一些生成式的方法值得探究.
總的來說, 基于缺陷庫抽取的方法利用了現(xiàn)有的人工審查后的缺陷資源, 因此在缺陷來源上可靠性較高.使用該類方法構(gòu)造的缺陷代碼數(shù)據(jù)集, 其主要針對的是具有CVE編碼的真實(shí)軟件缺陷, 可以認(rèn)為其樣本較為貼近缺陷檢測理想的使用場景. 但是, 由于缺陷庫需要相關(guān)人員的審查, 因此即使經(jīng)過數(shù)十年的積累(如NVD), 現(xiàn)有的缺陷庫中可被用于抽取樣本的缺陷條目數(shù)量仍然極為有限.
2.1.3
基于開源代碼庫爬取
從缺陷庫抽取缺陷數(shù)據(jù)較為可靠, 但缺陷庫中的可用數(shù)據(jù)量較少. Bhandari等人[59]的實(shí)證研究表明, NVD代碼庫中的171 178條缺陷數(shù)據(jù)中, 只有5 300余條能夠鏈接到對應(yīng)的提交代碼, 對齊率不足3.2%. 而GitHub等開源代碼庫中擁有海量的代碼提交, 其中擁有大量的缺陷提交與修復(fù)提交, 這些均可被挖掘作為缺陷條目. 由于人工成本等原因, 很多缺陷相關(guān)提交并未與CVE關(guān)聯(lián), 甚至沒有顯式的文字描述信息. 因此, 如何判別缺陷相關(guān)提交、如何挖掘代碼庫中的非標(biāo)記缺陷條目, 成為了擴(kuò)增缺陷代碼數(shù)據(jù)集的重要方向.
一種自動(dòng)獲取缺陷數(shù)據(jù)的路線是啟發(fā)式搜索.
Karampatsis等人[60]聚焦于在單語句中可完成修改的缺陷, 構(gòu)造了針對Java語言的單語句缺陷代碼數(shù)據(jù)集ManySStuBs4J. 其選定最熱門的1 000個(gè)開源Java Maven項(xiàng)目, 從其GitHub倉庫中爬取歷史提交, 通過安全相關(guān)關(guān)鍵詞(error、bug、fix等)對其進(jìn)行篩選, 并只保留在單語句中對缺陷進(jìn)行修復(fù)的提交. ManySStuBs4J數(shù)據(jù)集最終包含153 652條單語句修復(fù)缺陷. 該數(shù)據(jù)集已開源(https://doi.org/10.5281/zenodo.3653444).
為了測試對跨函數(shù)缺陷的檢測效果, Li等人[61]從開源網(wǎng)站挖掘了一個(gè)函數(shù)級Java語言缺陷代碼數(shù)據(jù)集.其使用關(guān)鍵詞匹配的啟發(fā)式方法從8個(gè)著名開源Java項(xiàng)目的倉庫中爬取缺陷修復(fù)報(bào)告, 將修復(fù)前后的整個(gè)項(xiàng)目下載, 通過缺陷修復(fù)時(shí)的添加與刪除操作定位缺陷函數(shù). 不過, 其并未對標(biāo)簽的情況進(jìn)行人工驗(yàn)證. 最終, 該數(shù)據(jù)集包含497萬個(gè)函數(shù), 其中, 182萬個(gè)為缺陷函數(shù), 占比36.7%. 雖然該數(shù)據(jù)集被用來測試跨函數(shù)的檢測效果, 但其在樣本的標(biāo)注中只對缺陷函數(shù)進(jìn)行了標(biāo)注, 而并未將其相關(guān)函數(shù)也生成標(biāo)注. 該數(shù)據(jù)集已開源(https://github.com/OOPSLA-2019-BugDetection/OOPSLA-2019-BugDetection).
啟發(fā)式搜索的規(guī)則較為簡單, 因此準(zhǔn)確性難以得到保障, 可能會(huì)為數(shù)據(jù)集帶來較多噪聲. 為此, 研究者們開始探究通過學(xué)習(xí)的方式進(jìn)行更精確的判斷與挖掘.
Zhou等人[62]分別訓(xùn)練了6個(gè)基礎(chǔ)分類器(隨機(jī)森林、樸素貝葉斯、K近鄰等), 并通過邏輯回歸來對其分類結(jié)果進(jìn)行整合, 從而自動(dòng)判斷代碼提交或問題報(bào)告是否與缺陷相關(guān). 該系統(tǒng)僅對提交的自然語言部分進(jìn)行分類, 而不考慮代碼部分的信息. 該系統(tǒng)可以實(shí)時(shí)監(jiān)控項(xiàng)目提交, 并不斷向數(shù)據(jù)集中補(bǔ)充樣本. 其從GitHub、JIRA、Bugzilla中挖取Java、Python、Ruby、JavaScript、Objective C和Go語言共計(jì)8 546個(gè)項(xiàng)目的提交信息與問題報(bào)告. 最終, 其提交的數(shù)據(jù)集中包含12 409個(gè)提交, 其中, 1 303個(gè)為缺陷提交, 占比10.5%. 問題報(bào)告數(shù)據(jù)集中包含24 188個(gè)問題報(bào)告, 其中, 1 905個(gè)為缺陷報(bào)告, 占比7.9%. 其安全團(tuán)隊(duì)通過兩輪的標(biāo)注對數(shù)據(jù)標(biāo)簽進(jìn)行驗(yàn)證. 不過, 該數(shù)據(jù)集未開源.
Sabetta等人[63]也嘗試自動(dòng)判別代碼提交以篩選出安全相關(guān)提交, 其在考慮自然語言信息的基礎(chǔ)上, 也將源代碼的修改加入?yún)⒖? 其構(gòu)建了兩個(gè)分類器, 分別依靠提交中的自然語言信息與代碼修改信息進(jìn)行安全判斷. 對于提交日志信息, 其使用詞袋模型對其進(jìn)行編碼, 使用支持向量機(jī)進(jìn)行分類; 對于代碼修改信息, 其將源代碼修改視為自然語言中的文本撰寫, 因此直接使用標(biāo)準(zhǔn)的文本分類方法對其進(jìn)行操作. 其只使用代碼中的標(biāo)識符名稱序列來表示代碼, 同樣使用詞袋模型加以表示, 并使用支持向量機(jī)進(jìn)行分類. 實(shí)驗(yàn)結(jié)果顯示: 該方法對安全相關(guān)提交的分類精確度有所提高, 但F1值為0.64, 還有較大空間.
Wang等人[64]提出了一種自動(dòng)的數(shù)據(jù)挖掘與標(biāo)注流程. 該數(shù)據(jù)集從Sard、NVD及GitHub中挖掘缺陷相關(guān)提交(commit). 對于GitHub中的無標(biāo)簽數(shù)據(jù), 其首先挑選高星值的項(xiàng)目爬取只修改單個(gè)文件的提交, 然后使用5種機(jī)器學(xué)習(xí)分類器進(jìn)行共同投票, 包括SVM、LR、KNN、RF、GB, 以判斷該提交是否引入了缺陷. 這些分類器是用3 000個(gè)人工標(biāo)記的提交訓(xùn)練的. 為了保證分類器判斷的準(zhǔn)確性, 5個(gè)分類器投票結(jié)果高度一致的提交才會(huì)被保留. 最終, 這些提交會(huì)按照函數(shù)級進(jìn)行分割. 該數(shù)據(jù)集最終獲得了150 950條函數(shù)級的代碼樣本, 語言涵蓋C、Java、PHP和Swift, CWE缺陷類型達(dá)到30種. 該數(shù)據(jù)集已開源(https://github.com/HuantWang/FUNDED_NISL).
上述部分研究使用了機(jī)器學(xué)習(xí)方法進(jìn)行自動(dòng)數(shù)據(jù)挖掘, 鑒于使用深度學(xué)習(xí)進(jìn)行文本分類已經(jīng)取得了較好的效果, 使用深度學(xué)習(xí)對代碼庫中的提交進(jìn)行自動(dòng)判斷也是一個(gè)值得探究的研究點(diǎn).
此外, 也有通過人工方式從開源代碼庫中挖掘缺陷數(shù)據(jù).
Zhou等人[65]為了獲得更加精確標(biāo)注的缺陷代碼數(shù)據(jù)集, 使用了純?nèi)斯?biāo)注的方式. 他們雇傭了一批安全人員對開源C/C++項(xiàng)目Linux Kernel、QEMU、Wireshard和FFmpeg進(jìn)行標(biāo)注. 首先對關(guān)鍵詞初篩后的安全相關(guān)提交(commit)進(jìn)行人工判斷是否與缺陷修復(fù)相關(guān), 然后將這些提交分割為函數(shù)級別的代碼段. 該數(shù)據(jù)集共使用4名安全研究員, 耗時(shí)600工時(shí)來完成兩輪的標(biāo)注與交叉驗(yàn)證. 最終, 該數(shù)據(jù)集共收納58 965個(gè)樣本函數(shù), 其中, 缺陷相關(guān)函數(shù)為27 652條, 占比46.9%, 正負(fù)樣本相對均衡. 該數(shù)據(jù)集目前開源了2個(gè)工程(FFmpeg與Qemu).
Cheng等人[66]構(gòu)建了一個(gè)混合來源的缺陷代碼數(shù)據(jù)集, 其從Sard缺陷庫與2個(gè)開源軟件(lua、redis)中抽取缺陷條目. 對于Sard數(shù)據(jù)集, 其只選取最常見缺陷類型TOP 10的條目. 對于開源項(xiàng)目, 其通過管檢測檢索安全相關(guān)提交后再使用人工審查進(jìn)行打標(biāo), 只選取缺陷修復(fù)提交前后的版本作為樣本, 該標(biāo)注工作花費(fèi)3人共720小時(shí). 在收集到函數(shù)級與文件級數(shù)據(jù)后, 根據(jù)系統(tǒng)API調(diào)用作為起點(diǎn)進(jìn)行前后向切片生成. 切片標(biāo)簽由其是否包含缺陷相關(guān)語句決定, 即: 若切片包含至少一條缺陷語句, 則將其標(biāo)記為“缺陷”. 在開源數(shù)據(jù)中, “缺陷語句”是根據(jù)修復(fù)提交的語句操作來判斷的. 為了方便與函數(shù)級缺陷檢測模型進(jìn)行對比, 所有數(shù)據(jù)還按照函數(shù)級進(jìn)行了上述標(biāo)記. 最終, 該數(shù)據(jù)集包含140 670個(gè)切片, 其中, 缺陷切片為44 521個(gè), 占比31.6%. 此外, 該數(shù)據(jù)集中Sard部分占比較大, 為98.3%. 該數(shù)據(jù)集已開源(https://github.com/DeepWukong/DeepWukong).
相對于自動(dòng)方法, 通過人工方式挖掘需要大量的人力成本, 且其標(biāo)注效率有限.
總的來說, 基于開源代碼庫爬取的方法可以得到大量的備選缺陷樣本, 但是爬取出的樣本是否為缺陷以及是哪種類型的缺陷都較難判斷: 自動(dòng)化的方法正確率難以保障, 而人工判斷的方法則在效率上制約了數(shù)據(jù)集的大小. 此外, 由于爬取代碼庫時(shí)大多采用啟發(fā)式的方法, 其爬取的缺陷樣本在形態(tài)上具有不確定性: 既可能包含具有CVE編號的真實(shí)、復(fù)雜缺陷, 也可能包含項(xiàng)目普通缺陷甚至簡單編碼錯(cuò)誤. 這種缺陷樣本的多樣性, 會(huì)對深度模型的設(shè)計(jì)提出較高的要求.
2.1.4
基于靜態(tài)分析工具生成
還有一種以相對低的成本快速獲取大量缺陷數(shù)據(jù)的方法, 即利用靜態(tài)分析工具對代碼進(jìn)行缺陷檢測, 從而得到缺陷樣本.
Russell等人[67]從Juliet、Debian Linux和GitHub中選擇了共12 874 380個(gè)C/C++函數(shù)段, 經(jīng)過去重篩選后, 對無標(biāo)簽的函數(shù)段(Juliet帶有標(biāo)簽)使用3種開源靜態(tài)分析工具Clang、Cppchecke和Flawfinder進(jìn)行缺陷檢測. 這3種分析工具擁有不同的檢測粒度, 通過投票的方式來共同對代碼段進(jìn)行是否含有缺陷的標(biāo)注. 最后, 通過人工的方式將分析工具報(bào)出的缺陷與CWE類型一一匹配對應(yīng). 最終, 該函數(shù)級缺陷代碼數(shù)據(jù)集包含1 286 262條樣本, 其中, 缺陷樣本為87 804條, 占比6.8%, 其類型對應(yīng)到CWE中有149個(gè)類型. 不過, 該數(shù)據(jù)集并未開源.
Dam等人[68]構(gòu)建了一個(gè)文件級的缺陷代碼數(shù)據(jù)集. 他們使用靜態(tài)分析工具(由于保密協(xié)議未透露)對開源項(xiàng)目Tizen進(jìn)行了檢測, 并只選取資源泄露相關(guān)警告. 該數(shù)據(jù)集基于C語言, 最終包含8 118個(gè)源文件, 其中, 2 887個(gè)為有缺陷文件, 達(dá)到35.6%. 不過, 該數(shù)據(jù)集并未開源.
總的來說, 使用靜態(tài)分析工具可以利用其分析能力生成較大數(shù)據(jù)量的標(biāo)注數(shù)據(jù). 但是靜態(tài)分析工具判別能力有限, 其誤報(bào)率高等缺陷在實(shí)踐中已被廣泛證實(shí), 因此, 使用靜態(tài)分析工具得到的判別結(jié)果作為標(biāo)準(zhǔn)答案在可靠性上沒有保證. 此外, 使用靜態(tài)分析工具構(gòu)造樣本, 其數(shù)據(jù)集的表征能力上界即為分析工具的檢測能力, 在此數(shù)據(jù)集上訓(xùn)練出的模型, 其效果只會(huì)低于直接使用分析工具, 因此, 使用深度模型意義不大. 而且, 由于當(dāng)前靜態(tài)分析工具大多關(guān)注相對(CVE)簡單的缺陷類型和代碼編碼規(guī)范, 因此由其構(gòu)造的數(shù)據(jù)集價(jià)值相對于真實(shí)工業(yè)缺陷來說偏低.
2.2
當(dāng)前數(shù)據(jù)集構(gòu)造方法存在的問題
為了便于對比, 我們對第2.1節(jié)中梳理的數(shù)據(jù)集構(gòu)造方法進(jìn)行列表展示. 對于每一種數(shù)據(jù)來源, 挑選至多3項(xiàng)代表性工作, 詳細(xì)列舉其各項(xiàng)統(tǒng)計(jì)信息, 包括其缺陷數(shù)據(jù)來源、擁有的缺陷類型(其中, “?”表示未區(qū)分類型)、數(shù)據(jù)樣本的粒度、數(shù)據(jù)集總樣本數(shù)、缺陷樣本數(shù)、缺陷樣本占比以及數(shù)據(jù)集是否開源.
統(tǒng)計(jì)結(jié)果見表 1, 可以看到: 當(dāng)前的缺陷代碼數(shù)據(jù)集在各項(xiàng)技術(shù)環(huán)節(jié)均存在較大的差異, 如不同的語言、粒度等. 對于從代碼庫爬取的缺陷數(shù)據(jù)集, 普遍存在沒有缺陷類型這一問題. 對于當(dāng)前絕大多數(shù)數(shù)據(jù)集, 均存在正負(fù)樣本不均衡的問題. 有接近半數(shù)的數(shù)據(jù)集未進(jìn)行開源, 給其他研究者進(jìn)行模型復(fù)現(xiàn)與橫向?qū)Ρ葞砹死щy.

表 1 數(shù)據(jù)集統(tǒng)計(jì)信息小結(jié)
此外, 我們在表 2中按照每個(gè)技術(shù)環(huán)節(jié)的技術(shù)路線列舉了至多3項(xiàng)代表性的工作, 并評估了每一類技術(shù)路線的優(yōu)缺點(diǎn).

表 2 數(shù)據(jù)集構(gòu)造方法小結(jié)
從數(shù)據(jù)來源上看, 不同的數(shù)據(jù)來源意味著其樣本復(fù)雜程度的不同. 例如, 在缺陷庫抽取中廣泛使用的NVD抽取數(shù)據(jù)與人工構(gòu)造中廣泛使用的Sard測試集數(shù)據(jù): 前者來源于真實(shí)的工業(yè)代碼, 其復(fù)雜程度較高, 且模塊化程度高, 各組件之間的依賴關(guān)系與調(diào)用關(guān)系復(fù)雜; 后者來源于人工撰寫的測試用例, 其復(fù)雜程度低, 且主要針對缺陷的表示, 而大多忽略其真實(shí)的功能, 因此為獨(dú)立程序片段, 幾乎沒有組件之間的長程依賴與復(fù)雜的調(diào)用關(guān)系. 從實(shí)際應(yīng)用的角度看, 缺陷檢測系統(tǒng)需要具備對真實(shí)工業(yè)代碼的檢測能力, 即理想的缺陷代碼數(shù)據(jù)集應(yīng)該來源于NVD等工業(yè)代碼而非人工撰寫的測試用例. 但工業(yè)代碼缺陷數(shù)據(jù)的獲取難度與成本遠(yuǎn)大于測試用例, 需要更加完善的樣本提取技術(shù)與大量不可避免的人工審查.
從數(shù)據(jù)粒度上看, 不同的數(shù)據(jù)粒度在完整度與冗余度上存在差距. 文件級數(shù)據(jù)可以包含較多路徑, 但不可避免地帶來大量的無關(guān)噪聲. 函數(shù)級數(shù)據(jù)在劃分時(shí)成本極低, 且在檢測過程中不需要對被測代碼進(jìn)行分析(切割為函數(shù)即可). 然而, 函數(shù)級數(shù)據(jù)基于的樸素假設(shè)是: 缺陷發(fā)生在函數(shù)的范圍內(nèi). 這在大規(guī)模工業(yè)代碼中顯然是難以支持的, 特別是在模塊化的情況下, 數(shù)據(jù)的聲明與使用往往不存在于單一函數(shù)中. 切片級數(shù)據(jù)可以支持跨函數(shù)的缺陷路徑, 但切片操作需要在構(gòu)建數(shù)據(jù)集與檢測被測代碼時(shí)均對代碼進(jìn)行數(shù)據(jù)流、控制流等分析, 對資源的需求較大, 時(shí)間成本也較高.
從標(biāo)注方式上看, 不同的標(biāo)注方式使得標(biāo)簽的精度與獲取成本存在差異. 安全相關(guān)人員的人工標(biāo)注能夠保證標(biāo)簽的質(zhì)量, 但其獲取成本較高, 且標(biāo)注速度較慢, 達(dá)到深度學(xué)習(xí)模型需要的數(shù)據(jù)規(guī)模需要長期的積累. 使用啟發(fā)式方法自動(dòng)化地進(jìn)行標(biāo)注可以快速、大量地生成標(biāo)注, 然而其標(biāo)注精度難以達(dá)到理想的標(biāo)注效果.
下面我們對一些具體問題進(jìn)行闡述.
2.2.1
不包含完整缺陷路徑
許多數(shù)據(jù)集[31?34, 41, 45, 64?67]是函數(shù)級數(shù)據(jù)集, 或者是先選定函數(shù)再在其內(nèi)部進(jìn)行切片操作. 但是對于函數(shù)的選擇往往是根據(jù)缺陷補(bǔ)丁位置(diff修改的函數(shù))來決定的, 而補(bǔ)丁位置并不一定與缺陷在同一函數(shù)中, 這樣會(huì)導(dǎo)致缺陷樣本不包含完整的觸發(fā)路徑. 例如圖 2-2所示, 該代碼示意圖包含2個(gè)函數(shù)A和B. 缺陷在函數(shù)B被觸發(fā), 但是由于缺陷修復(fù)被寫在了靠前的函數(shù)A, 即與函數(shù)B的觸發(fā)位置不在同一個(gè)函數(shù)中, 所以最終觸發(fā)缺陷的語句不包含在數(shù)據(jù)集中(只包含diff所在的函數(shù)). 因此, 若將函數(shù)A作為缺陷樣本, 則其不是一個(gè)完整的缺陷路徑. 這種情況在模塊化較為顯著的大型項(xiàng)目中更為突出.

圖 2-2 不包含完整缺陷路徑的代碼示意圖
若缺陷樣本不包含完整的缺陷流程, 特別是不包含最終的缺陷觸發(fā)位置, 則在此基礎(chǔ)上進(jìn)行的特征挖掘?qū)⑹ヒ饬x. 因此, 當(dāng)抽取缺陷樣本時(shí), 應(yīng)該考慮到跨函數(shù)的問題, 而不應(yīng)直接將代碼范圍限定在函數(shù)內(nèi)部.
2.2.2
正負(fù)樣本設(shè)置不合理
觀察一些數(shù)據(jù)集的構(gòu)造方法我們發(fā)現(xiàn), 一些數(shù)據(jù)集在構(gòu)造正樣本(缺陷樣本)與負(fù)樣本(非缺陷樣本)時(shí)不是針對同一個(gè)操作. 例如[42]: 將diff所在的函數(shù)標(biāo)記為缺陷函數(shù), 而其余的未被diff影響的函數(shù)標(biāo)記為非缺陷函數(shù). 事實(shí)上, 每個(gè)函數(shù)的功能是不同的, 其包含的操作也不相同. 例如: 對于CWE-119類型下的缺陷函數(shù), 其往往是負(fù)責(zé)處理緩沖區(qū)事務(wù), 因此包含較多緩沖區(qū)操作, 而其他函數(shù)并不一定有(且大概率沒有)如此多緩沖區(qū)操作. 因此, 將CWE-119類型缺陷函數(shù)以外的函數(shù)標(biāo)為非缺陷函數(shù), 可能會(huì)使得模型退化成對是否含有緩沖區(qū)操作或是否含有較多緩沖區(qū)操作的識別, 而不是對緩沖區(qū)操作是否正確的識別. 因此, 有必要將正負(fù)樣本限定在相同的操作行為中. 例如, 使用修改前后的代碼作為正負(fù)樣本, 就可以避免這類問題.
2.2.3
橫向比較問題
當(dāng)前, 基于深度學(xué)習(xí)的缺陷檢測任務(wù)分為不同的粒度, 如文件級缺陷檢測、函數(shù)級缺陷檢測、切片級缺陷檢測. 對于針對不同粒度的檢測系統(tǒng), 存在無法橫向比較的問題, 原因是不同粒度的標(biāo)答模式不好界定. 如圖 2-2所示, 若缺陷路徑由函數(shù)A到函數(shù)B, 那么對于函數(shù)級缺陷檢測, 需要單獨(dú)對函數(shù)A與函數(shù)B標(biāo)注, 此時(shí)對兩者標(biāo)注“缺陷”或“非缺陷”都是有爭議的.
3 基于深度學(xué)習(xí)的源代碼缺陷檢測模型
如果將代碼簡單認(rèn)為是一個(gè)文本符號序列, 則使用深度學(xué)習(xí)模型對代碼段進(jìn)行缺陷判斷類似于文本分類問題. 但是由于代碼本身的特性與缺陷檢測任務(wù)的特性, 其中包含許多技術(shù)難點(diǎn). 因此, 本節(jié)將列舉一些主要的技術(shù)難點(diǎn), 介紹當(dāng)前針對這些難點(diǎn)的研究方法.
3.1
代碼表征
由于代碼具備各個(gè)維度的特征, 例如局部的文本共現(xiàn)特征與長程的數(shù)據(jù)、控制依賴特征, 因此, 如何對代碼進(jìn)行表征成為了設(shè)計(jì)深度學(xué)習(xí)模型需首要考慮的問題. 當(dāng)前的方法主要通過序列、樹和圖對代碼進(jìn)行表征, 其常用的對應(yīng)網(wǎng)絡(luò)結(jié)構(gòu)如圖 3-1所示.

圖 3-1 代碼表征的分類與應(yīng)用模型
下面將依次對其相關(guān)研究進(jìn)行介紹.
3.1.1
基于序列的表征
由于深度學(xué)習(xí)在自然語言處理上的成功, 研究者很容易想到將其方法應(yīng)用到代碼語言上, 即將代碼通過序列的方式進(jìn)行表征.
針對現(xiàn)有漏洞檢測系統(tǒng)依賴人類專家定義特征、經(jīng)常出現(xiàn)高漏報(bào)的問題, Li等人[42]提出了VulDeePecker, 這是一個(gè)基于深度學(xué)習(xí)的漏洞檢測系統(tǒng). 在輸入上, 其使用代碼片段作為輸入粒度, 因此對于輸入代碼均需檢測危險(xiǎn)函數(shù)調(diào)用作為入口并進(jìn)行切片組合. VulDeePecker選擇了循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)模型, 并使用雙向長短期記憶(bi-LSTM)來解決梯度消失與前后向依賴問題, 因?yàn)槌绦蚝瘮?shù)調(diào)用的參數(shù)可能會(huì)受到較早或較晚語句的影響, 其使用Word2Vec將輸入的代碼片段轉(zhuǎn)化為向量表示投入Bi-LSTM網(wǎng)絡(luò)進(jìn)行訓(xùn)練. Bi-LSTM網(wǎng)絡(luò)并未作特殊設(shè)計(jì). 實(shí)驗(yàn)結(jié)果表明: VulDeePecker總體檢測的F1值達(dá)到90.5, 顯著高于使用傳統(tǒng)方法(基于模式與基于代碼相似度)的缺陷檢測系統(tǒng), 并且可以大幅降低誤報(bào)率. 不過, 該模型并未開源.
由于VulDeePecker只使用了Bi-LSTM, Li等人[44]進(jìn)一步測試了多種模型構(gòu)架, 包括GRU、DBN、MLP等. 其最終確認(rèn)雙向門控循環(huán)單元(bi-GRU)擁有更好的檢測效果. 基于Bi-GRU的SySeVR模型在4個(gè)真實(shí)的工程(Libav、Seamonkey、Thunderbird、Xen)上檢測出15個(gè)缺陷, 其中, 7個(gè)為尚未發(fā)覺的缺陷. 不過, 該模型并未開源.
Xu等人[30]首先對程序根據(jù)調(diào)用情況進(jìn)行切片以保留相關(guān)語句, 然后通過正規(guī)化去除命名影響, 最后將其轉(zhuǎn)化為向量形式作為模型輸入. 在分類模型上, 其將CNN與RNN結(jié)合成一個(gè)網(wǎng)絡(luò), 稱為“Contextual LSTM”.具體來說, 其首先通過CNN來挖掘局部特征, 然后投入LSTM來挖掘前后的依賴特征. 實(shí)驗(yàn)結(jié)果顯示: CLSTM在Sard數(shù)據(jù)集上, F1可高達(dá)0.97, 高于對比的CNN與LSTM模型, 但提高不顯著.
借鑒自然語言處理中的情感分析任務(wù), Russell等人[67]設(shè)計(jì)了一個(gè)基于表示學(xué)習(xí)的源代碼分類器. 其首先將源代碼按照詞法進(jìn)行嵌入表示, 在特征提取階段, 通過多層的卷積來挖掘局部特征或通過循環(huán)迭代來捕捉前后的依賴關(guān)系. 隨后, 通過池化層和全連接層得到最終的函數(shù)表示. 由于表示學(xué)習(xí)已經(jīng)學(xué)習(xí)到了函數(shù)的特征, 因此最后對函數(shù)的缺陷檢測就可以通過將其表示直接投入隨機(jī)森林分類器即可完成. 實(shí)驗(yàn)結(jié)果顯示: 使用表示學(xué)習(xí)連接隨機(jī)森林分類器的方法比單純使用詞袋模型連接隨機(jī)森林的效果提高較多, 其檢測效果也顯著高于選擇的3種靜態(tài)分析工具(Clang/Flawfinder/Cppchecker). 不過, 該模型并未開源.
Choi等人[39]借鑒了自動(dòng)問答領(lǐng)域的模式來判斷緩沖區(qū)調(diào)用是否安全. 其使用了記憶網(wǎng)絡(luò)的框架, 將緩沖區(qū)調(diào)用語句作為查詢語句, 將緩沖區(qū)相關(guān)的初始化與分配語句作為需要查詢的相關(guān)內(nèi)容, 最終幫助模型進(jìn)行安全性的判斷. 具體來說, 其首先將代碼按照詞進(jìn)行嵌入編碼, 將待查詢的上下文語句通過矩陣表示為記憶值模塊與記憶地址模塊, 再通過注意力機(jī)制, 使用查詢(緩沖區(qū)調(diào)用)語句得到相關(guān)記憶語句的排序, 最終通過檢索出的相關(guān)語句進(jìn)行訪問操作是否安全的判斷. 實(shí)驗(yàn)結(jié)果顯示: 該模型在4種復(fù)雜度級別的緩沖區(qū)操作的判斷中均高于傳統(tǒng)的CNN與LSTM模型, 在復(fù)雜度較高的情況下優(yōu)勢更加顯著. 不過, 該模型并未開源.
事實(shí)上, 代碼中包含了許多自然語言上的信息, 例如變量和函數(shù)的命名等. 這些信息可以指示該變量或函數(shù)的功能與屬性, 這種提示信息在擁有標(biāo)準(zhǔn)命名規(guī)則的大型工程中尤為明顯. Pradel等人[37]就利用了這樣的信息, 依靠深度學(xué)習(xí), 僅僅針對命名信息進(jìn)行缺陷檢測. 其通過Word2Vec對命名進(jìn)行了嵌入式的向量表示, 以便模型挖掘其語義上的信息. 在分類模型上, 其選用了最基礎(chǔ)的前饋神經(jīng)網(wǎng)絡(luò), 沒有進(jìn)行特殊的設(shè)計(jì). 實(shí)驗(yàn)結(jié)果顯示, DeepBugs模型在數(shù)據(jù)集上的檢測準(zhǔn)確率超過89%. 在針對真實(shí)代碼的檢測中, 人工審查其150個(gè)缺陷報(bào)告后, 確認(rèn)其中102個(gè)為正確的缺陷報(bào)出, 判斷精度達(dá)到68%, 證明了即使使用人工構(gòu)造的缺陷數(shù)據(jù)集也可以賦予模型挖掘真實(shí)缺陷的能力. 在效率上, 其單個(gè)文件的檢測時(shí)常不超過20 ms, 也顯示了其可用性.但是, 該模型的挖掘能力局限于生成缺陷代碼的變異模式, 而不具備較好的擴(kuò)展性. 該模型現(xiàn)已開源(https://github.com/michaelpradel/DeepBugs).
Saccente等人[33]提出了原型工具Project Achilles, 其使用LSTM網(wǎng)絡(luò)對Java代碼作函數(shù)級缺陷檢測. 不同于其他方法使用單一模型對待測樣本進(jìn)行判斷, Project Achilles針對其訓(xùn)練數(shù)據(jù)中的每一個(gè)類型都訓(xùn)練了一個(gè)基于LSTM的分類器, 因此會(huì)對待測樣本是否是某個(gè)類型的缺陷都進(jìn)行一次評估. 這樣, Project Achilles不僅可以判斷待測樣本是否有缺陷, 同時(shí)也能直接得到該缺陷的類型. Project Achilles按token序列來讀入函數(shù)代碼, 在LSTM模型上, 其并未作特殊修改. 盡管一些類型只有100多個(gè)文件的數(shù)據(jù)作為訓(xùn)練樣本, Project Achilles仍然在29個(gè)CWE類型中的24個(gè)上達(dá)到了超過90%的準(zhǔn)確率. 該模型已開源(https://gitlab.com/TUSoftwareEngineering/vulnerabilitylocalization-using-machine-learning).
除了傳統(tǒng)的分類模型, 有些研究還嘗試了新的模型架構(gòu), 例如使用seq2seq的方法進(jìn)行缺陷檢測.
為了只使用缺陷代碼和其對應(yīng)的修改后代碼進(jìn)行缺陷檢測, Grag等人[69]提出了一個(gè)基于機(jī)器翻譯模型的檢測系統(tǒng). 其將缺陷代碼視為源語言, 將其修復(fù)版本視為目標(biāo)語言, 通過基于RNN的編碼器與解碼器來學(xué)習(xí)其中的差異與轉(zhuǎn)化方式. 同時(shí), 還使用修復(fù)代碼作為源語言, 同一修復(fù)代碼作為目標(biāo)語言, 來使模型不對正確的代碼做轉(zhuǎn)化. 最終在檢測時(shí), 若翻譯模型未對輸入代碼進(jìn)行修改, 則認(rèn)定其為無缺陷的正確代碼. 實(shí)驗(yàn)結(jié)果顯示: 該方法在無噪聲和有噪聲的情況下檢測效果均好于傳統(tǒng)特征挖掘模型, 在有噪聲條件下效果更顯著. 不過, 其未與深度學(xué)習(xí)模型進(jìn)行比較, 也未開源.
傳統(tǒng)的缺陷檢測方法針對不同的缺陷類型預(yù)設(shè)了不同的缺陷模式, 通過匹配的方式, 在判斷代碼是否含有缺陷的同時(shí), 也可以得到其所屬的缺陷類型信息. 而基于深度學(xué)習(xí)的缺陷檢測系統(tǒng)往往只對代碼做二分類, 即判斷其是否含有缺陷, 而無法提供其缺陷類型, 這給開發(fā)人員帶來了一些不便因素.
為此, Zou等人[43]提出了第一個(gè)多分類的深度學(xué)習(xí)缺陷檢測系統(tǒng)μVulDeePecker. 該系統(tǒng)定義了代碼注意力, 即: 在輸入的代碼片段中選定符合缺陷語法特征規(guī)則的語句子集, 從而更好地挖掘缺陷的局部特征. 該缺陷語法特征規(guī)則是通過人工總結(jié)得到的, 包括庫/API函數(shù)調(diào)用中參數(shù)的定義語句、控制語句及包含庫/API函數(shù)調(diào)用的語句. 其將代碼片段與對應(yīng)的代碼注意力片段分別編碼并向量化, 同時(shí)作為該段代碼的表征投入Bi-LSTM進(jìn)行多分類任務(wù)的訓(xùn)練. 實(shí)驗(yàn)結(jié)果顯示: μVulDeePecker模型在多分類任務(wù)上的效果好于單獨(dú)將VulDeePecker模型修改為多分類的版本, 在個(gè)別類型上效果尤為顯著. 引入的控制依賴對模型有較大的性能提升. 該模型未開源.
近年來, 大規(guī)模預(yù)訓(xùn)練語言模型(如BERT[70])在自然語言領(lǐng)域展現(xiàn)出的優(yōu)良效果為程序語言研究者們提供了一種新的程序表示思路, 人們也開始探究基于Transformer在程序語言上構(gòu)建預(yù)訓(xùn)練模型, 其中部分研究將缺陷檢測作為下游任務(wù)進(jìn)行了初步的探究.
考慮到相關(guān)人員編寫代碼時(shí)會(huì)通過附加自然語言的注解與其他人員溝通, 一些研究者試圖利用自然語言來幫助更好地挖掘與建模程序語言. Feng等人[71]提出了CodeBERT, 該預(yù)訓(xùn)練模型使用程序語言與自然語言共同預(yù)訓(xùn)練. 其使用了兩個(gè)目標(biāo)任務(wù)進(jìn)行訓(xùn)練, 分別為掩碼語言建模和替換令牌檢測. 為了測試代碼預(yù)訓(xùn)練模型在非訓(xùn)練任務(wù)的可用性, Zhou等人[72]將CodeBERT在實(shí)時(shí)缺陷檢測任務(wù)上進(jìn)行了實(shí)驗(yàn)(值得說明的是: 實(shí)時(shí)缺陷檢測任務(wù)同時(shí)將提交代碼與提交的自然語言信息作為輸入來判斷該提交是否引入了缺陷, 與傳統(tǒng)的缺陷檢測任務(wù)只輸入代碼存在一定差異). 實(shí)驗(yàn)結(jié)果表明, 簡單地將CodeBERT替換原模型的編碼器即可接近SOTA的性能, 這表明了代碼預(yù)訓(xùn)練模型的語義捕獲能力沒有局限在其訓(xùn)練任務(wù)中. 該實(shí)驗(yàn)已開源(https://github.com/Xin-Zhou-smu/Assessing-generalizability-of-CodeBERT).
不過, 實(shí)時(shí)缺陷檢測任務(wù)雖然與源代碼缺陷檢測任務(wù)同為判斷代碼是否有缺陷, 但兩者的輸入存在差異.因此, 代碼預(yù)訓(xùn)練語言模型在缺陷檢測任務(wù)上的效果還需要進(jìn)一步地實(shí)驗(yàn)證實(shí).
Ahmad等人[73]提出了一種能夠執(zhí)行廣泛的程序-自然語言的理解-生成任務(wù)(program and language understanding and generation)的預(yù)訓(xùn)練模型PLBART, 其通過去噪自動(dòng)編碼對大量Java和Python函數(shù)以及相關(guān)的自然語言文本進(jìn)行了預(yù)訓(xùn)練. 具體來說, 其在StackOverflow上抓取大量問題、答案與代碼段, 投入與BART[74]相同的結(jié)構(gòu), 并引入了3種噪聲: 令牌掩碼、令牌刪除與令牌填充使得模型能夠推理語言語法和語義, 并同時(shí)學(xué)習(xí)連貫地生成語言. 為了檢測PLBART對未見代碼語言的理解能力, 其在基于C/C++語言的缺陷檢測任務(wù)上進(jìn)行了測試. 但是, 只對比了其他的語言模型, 并未與針對缺陷檢測任務(wù)的深度學(xué)習(xí)模型進(jìn)行比較. Ahmad等人表示: 當(dāng)前, 基于圖的缺陷檢測模型效果最好, 使用缺陷檢測任務(wù)只是用來探究預(yù)訓(xùn)練語言模型在未見任務(wù)與未見語言上對程序語義的性能. 該模型已開源(https://github.com/wasiahmad/PLBART).
由此可見, 預(yù)訓(xùn)練代碼語言模型在挖掘程序語義上具備一定的潛力, 但當(dāng)前的研究還未統(tǒng)一在源代碼缺陷檢測的場景下橫向?qū)Ρ壬疃葘W(xué)習(xí)模型與預(yù)訓(xùn)練語言模型的性能差異, 未來還需要進(jìn)一步地深入探究. 總的來說, 基于序列的表征較為直觀, 且不需要對待測代碼進(jìn)行額外的分析處理, 在實(shí)現(xiàn)上較為簡便. 但是不同于自然語言, 代碼語言具有更強(qiáng)的結(jié)構(gòu)性與局部性, 其上下文的依賴關(guān)系更為復(fù)雜且距離更長, 因此, 單純地使用序列作為代碼表征會(huì)損失大量的代碼結(jié)構(gòu)特征. 由于基于序列的表征存在的這類問題, 后期研究大多不再使用序列作為表征方式.
3.1.2
基于樹的表征
在對代碼進(jìn)行分析時(shí), 除了以序列的形式以外, 最常用的就是抽象語法樹(AST)的形式.
Li等人[53]提出了基于卷積神經(jīng)網(wǎng)絡(luò)的DP-CNN模型. 該模型針對文件級缺陷檢測, 并將抽象語法樹作為代碼原始表征以獲取更多的結(jié)構(gòu)信息. 其首先將文件代碼解析為抽象語法樹, 然后從中選擇代表性節(jié)點(diǎn)構(gòu)成表示該文件的向量, 轉(zhuǎn)化為詞嵌入形式后投入卷積神經(jīng)網(wǎng)絡(luò)模型進(jìn)行特征的學(xué)習(xí), 最終學(xué)習(xí)得到的表示特征與一些傳統(tǒng)特征混合投入邏輯回歸分類器進(jìn)行分類. 在DP-CNN系統(tǒng)中, 其選擇的代表性節(jié)點(diǎn)是人工設(shè)定的, 包括方法調(diào)用和類實(shí)例創(chuàng)建的節(jié)點(diǎn)、聲明節(jié)點(diǎn)與控制流節(jié)點(diǎn). 為了解決缺陷樣本少的問題, DP-CNN在訓(xùn)練階段會(huì)重復(fù)使用缺陷樣本. 實(shí)驗(yàn)結(jié)果顯示: 該方法在其數(shù)據(jù)集上的檢測高于使用深度置信網(wǎng)絡(luò)的方法, 但整體檢測性能有限, F1值僅為0.6. 該模型未開源.
Lin等人[41]使用了樹結(jié)構(gòu)作為代碼的表征. 具體地, 其使用代碼解析工具CodeSensor將函數(shù)代碼轉(zhuǎn)化為AST, 并使用深度優(yōu)先遍歷將其轉(zhuǎn)化為序列表示; 隨后進(jìn)行截?cái)嗪脱a(bǔ)零使其成為等長語句; 最后, 使用Word2Vec將其轉(zhuǎn)化為向量形式. 在模型上, 該方法使用Bi-LSTM模型來捕獲缺陷特征, 模型結(jié)構(gòu)未作特殊修改. 在訓(xùn)練完成后, 將具有少量標(biāo)簽的目標(biāo)代碼輸入訓(xùn)練好的模型以獲得其表示并判斷缺陷. 實(shí)驗(yàn)結(jié)果顯示, 使用表示學(xué)習(xí)的方法在TOP 10缺陷函數(shù)的檢測效果顯著優(yōu)于基于代碼度量的方法. 但是, 該模型的整體誤報(bào)率較高, 使其可用性不佳.
Dam等人[68]使用了基于樹結(jié)構(gòu)的LSTM網(wǎng)絡(luò)來對通過AST表征的代碼進(jìn)行缺陷檢測, 具體地, 該模型首先將一個(gè)源文件清洗并解析為抽象語法樹, 每一個(gè)節(jié)點(diǎn)按照其類型名稱進(jìn)行嵌入式表示, 將每一個(gè)節(jié)點(diǎn)都投入LSTM單元從而表征整個(gè)代碼文件, 最終通過傳統(tǒng)分類器(邏輯回歸與隨機(jī)森林)對整個(gè)源文件的AST特征向量表示進(jìn)行缺陷判斷. 實(shí)驗(yàn)結(jié)果顯示: 該模型在工程內(nèi)的數(shù)據(jù)集下的缺陷檢測F1值達(dá)到0.9以上, 但在跨工程的數(shù)據(jù)集下F1值只有0.5.
針對現(xiàn)有方法無法較好地處理跨函數(shù)缺陷的問題, Li等人[61]提出了一種結(jié)合使用上下文和注意力神經(jīng)網(wǎng)絡(luò)的方法. 其首先基于AST對函數(shù)代碼進(jìn)行向量表征作為局部上下文, 再對AST上的路徑節(jié)點(diǎn)使用程序依賴圖和數(shù)據(jù)流作為全局上下文, 以將待測函數(shù)與可能導(dǎo)致錯(cuò)誤代碼的其他相關(guān)函數(shù)連接起來. 通過增加對上下文的表示, 減少因?yàn)榫植看a相似度而導(dǎo)致的誤報(bào). 同時(shí), 為了避免上下文的引入使得代碼相似度匹配過于嚴(yán)苛, 其使用注意力機(jī)制來增加缺陷路徑的權(quán)重, 從而保證召回率. 在與基于規(guī)則的檢測工具和基于挖掘的方法比較的過程中, 該方法均大幅優(yōu)于對比方法, 但整體效果有限: 在難度相對低的項(xiàng)目內(nèi)檢測中, F1值為0.64. 該模型已開源(https://github.com/OOPSLA-2019-BugDetection/OOPSLA-2019-BugDetection).
在對代碼進(jìn)行表示時(shí), 傳統(tǒng)方法會(huì)使用定長向量, 這就需要對代碼內(nèi)容進(jìn)行截?cái)?代碼過長)或填充(代碼過短), 這會(huì)帶來信息的丟失或冗余. Feng等人[34]提出了一種基于抽象語法樹的數(shù)據(jù)處理方法來提取所有句法特征并減少數(shù)據(jù)冗余, 其在雙向門控循環(huán)單元(bi-GRU)網(wǎng)絡(luò)上應(yīng)用包填充(pack-padded)方法來訓(xùn)練可變長度數(shù)據(jù)而無需對變量截?cái)嗪吞畛? 具體來說, 其首先將程序源代碼解析為AST, 并按照函數(shù)節(jié)點(diǎn)進(jìn)行切割, 得到按照函數(shù)分割的AST. 然后遍歷整個(gè)AST, 并將所有用戶定義的名稱映射到固定的預(yù)設(shè)名稱模式, 以消除不同命名帶來的差異. 為了能夠作為深度神經(jīng)網(wǎng)絡(luò)的輸入, 其通過前序遍歷將AST轉(zhuǎn)換為節(jié)點(diǎn)序列, 并使用Word2Vec將節(jié)點(diǎn)序列映射為向量表示. 在網(wǎng)絡(luò)模型上, 該方法使用雙向門控循環(huán)單元來應(yīng)對函數(shù)級表示帶來的長向量. 其在模型結(jié)構(gòu)上沒有特殊改動(dòng), 所不同的是, 其使用了包填充方法來應(yīng)對可變長度向量, 即針對不同的輸入長度進(jìn)行記錄并同時(shí)輸入模型, 而不需要將向量長度統(tǒng)一化. 實(shí)驗(yàn)結(jié)果顯示, 該模型在3種數(shù)據(jù)集劃分下均達(dá)到了0.82以上的F1值. 相對于開源分析工具Rats和Flawfinder, 該模型具有更高的準(zhǔn)確率, 同時(shí)誤報(bào)率也更低. 不過, 該模型未開源.
總的來說, 相較于基于序列的表征方式, 基于樹的表征可以更好地顯式表征代碼中的結(jié)構(gòu)信息, 在傳統(tǒng)缺陷檢測方法中也大多會(huì)選用抽象語法樹作為分析對象. 但事實(shí)上, 除了抽象語法樹能夠表示的結(jié)構(gòu)信息以外, 源代碼本身還具備數(shù)據(jù)流、控制流等多種不同維度的特征, 而這些特征在缺陷檢測的過程中恰恰是較為關(guān)鍵的部分. 因此, 單純地使用抽象語法樹作為代碼表征是不夠的.
3.1.3
基于圖的表征
基于序列或樹的缺陷檢測在學(xué)習(xí)全面的程序語義以表征真實(shí)源代碼漏洞高度的多樣性和復(fù)雜性方面具有很大的局限性. 程序語言不同于自然語言, 其更具有結(jié)構(gòu)性與層次性, 并且具有抽象語法樹、數(shù)據(jù)流、控制流等多種不同維度的表示模式. 根據(jù)缺陷類型的不同, 需要考慮的維度也不同, 單純地使用平面序列或語法樹來表征代碼會(huì)嚴(yán)重限制模型覆蓋各種缺陷的能力.
由于圖神經(jīng)網(wǎng)絡(luò)與代碼的各種屬性圖可以較好地適配, 因此逐漸成為人們在缺陷檢測任務(wù)上的熱點(diǎn)模型. 其中, 如何構(gòu)建圖以建模表征代碼是最關(guān)鍵的探究點(diǎn).
在代碼場景中, 缺陷代碼和非缺陷代碼有時(shí)相似度較高, 例如僅在單個(gè)保護(hù)數(shù)值或邊界條件上有細(xì)微差異, 而在其他操作上完全一致. 這類細(xì)小的差異往往難以被模型捕獲. 針對這個(gè)問題, Duan等人[31]提出了VulSniper模型, 其使用attention機(jī)制來捕獲代碼的關(guān)鍵部位. 具體來說, 其首先從源代碼生成程序?qū)傩詧D(code property graph)以盡可能地保留更多信息, 隨后將程序?qū)傩詧D轉(zhuǎn)化為一個(gè)144維的特征向量作為模型輸入, 并通過attention機(jī)制來計(jì)算不同節(jié)點(diǎn)的權(quán)重, 最后通過全連接層進(jìn)行二分類判斷代碼是否有缺陷. 其中, attention部分分別使用多個(gè)一維卷積和一維卷積的轉(zhuǎn)置來實(shí)現(xiàn)自底向上和自頂向下的結(jié)構(gòu). 通過一維卷積, 感受野逐漸擴(kuò)大以獲得周圍和全局信息. 通過一維卷積的轉(zhuǎn)置, 將高級特征縮放到與輸入相同的大小, 以便將注意力權(quán)重應(yīng)用于輸入. VulSniper針對的是函數(shù)級的缺陷檢測任務(wù), 其在Sard數(shù)據(jù)集中緩沖區(qū)錯(cuò)誤(CWE-119)和資源管理(CWE-399)這兩個(gè)缺陷類型上的F1值達(dá)到了80.6%和73.3%, 遠(yuǎn)超傳統(tǒng)方法. 不過, 該模型并未開源.
Zhou等人[65]提出的Devign模型基于AST來表征代碼, 并將不同層級的控制流、數(shù)據(jù)依賴、自然代碼序列顯式編碼為異構(gòu)邊的聯(lián)合圖, 每種類型表示與相應(yīng)表示相關(guān)的連接. 這種綜合表示方法有助于捕獲盡可能廣泛的漏洞類型和模式, 并能夠通過圖神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)更好的節(jié)點(diǎn)表示. 在模型上, Devign使用帶有Conv模塊的門控圖神經(jīng)網(wǎng)絡(luò). 有別于使用全部節(jié)點(diǎn)進(jìn)行分類, Conv模塊可以在學(xué)習(xí)到的豐富節(jié)點(diǎn)表示中提取有用的特征用于圖級分類. 實(shí)驗(yàn)結(jié)果顯示: Devign在缺陷檢測任務(wù)的效果上顯著高于之前方法; 同時(shí), 其在112個(gè)真實(shí)項(xiàng)目的缺陷函數(shù)中檢測準(zhǔn)確率達(dá)到74%, 顯示了其在現(xiàn)實(shí)應(yīng)用上的可能性. 不過, 該模型并未開源.
Feng等人[75]同樣使用圖來表征程序代碼, 并通過GNN來對其進(jìn)行分類, 并探究了不同模塊的不同設(shè)置帶來的影響. 其測試使用了不同屬性圖表征(AST、CFG、CPG)、不同編碼方式(Bag-Of-Words、Word2Vec、隨機(jī))和不同GNN學(xué)習(xí)方法(DiffPool、Set2Set、DGCNN). 實(shí)驗(yàn)初步結(jié)果顯示: AST+Word2Vec+DiffPool是當(dāng)前效果最好的組合, 相較于靜態(tài)分析工具(Cppchecker、Clang、Flawfinder)有較大的性能優(yōu)勢.
Ghaffarian等人[35]設(shè)計(jì)了一種定制的程序中間圖表示, 其使用抽象語法樹(abstract syntax tree, AST)、控制流圖(control flow graph, CFG)和程序依賴圖(program dependence graph, PDG)作為信息來源. 在圖的基礎(chǔ)上, 對節(jié)點(diǎn)和邊的文本信息(變量名、類型)使用TF-IDF進(jìn)行向量化. 在圖模型的選擇上, 其選用了圖卷積模型(graph convolutional network, GCN)與圖注意力模型(graph attention network, GAT), 其在網(wǎng)絡(luò)上沒有作特殊修改. 實(shí)驗(yàn)結(jié)果顯示: 圖卷積模型在7個(gè)缺陷類型上的F1值都顯著高于其他方法, 但圖注意力模型在跨項(xiàng)目檢測上的效果更好. 同時(shí), 相關(guān)實(shí)驗(yàn)還指出: 對程序進(jìn)行表征的向量程度不應(yīng)過小, 否則會(huì)影響圖神經(jīng)網(wǎng)絡(luò)的性能. 與一些研究會(huì)對代碼進(jìn)行規(guī)范化處理(替代變量名等)不同, 該研究通過實(shí)驗(yàn)特意指出, 規(guī)范化操作會(huì)影響模型辨別效果. 不過, 該研究的代碼并未開源.
傳統(tǒng)方法使用序列或無類型圖來表征代碼作為輸入, 這會(huì)丟失很多代碼結(jié)構(gòu)上的控制與依賴信息. Wang等人[64]提出了FUNDED, 它在抽象語法樹的基礎(chǔ)上, 人工定義了8種關(guān)系, 包括數(shù)據(jù)依賴關(guān)系、控制依賴關(guān)系、守護(hù)關(guān)系、跳轉(zhuǎn)關(guān)系、運(yùn)算關(guān)系、序列鄰接關(guān)系、最后使用關(guān)系、最后詞法使用關(guān)系, 以將抽象語法樹擴(kuò)增為一個(gè)有向多圖. FUNDED使用這9種關(guān)系(本身抽象語法樹的關(guān)系)得到的鄰接矩陣來表征整個(gè)函數(shù)代碼段, 從而使模型能夠獲得更多的語義、控制等信息. 該模型使用門控圖神經(jīng)網(wǎng)絡(luò)(GGNN)對表征函數(shù)的鄰接矩陣進(jìn)行分類, 其在自建數(shù)據(jù)集上獲得了較好的效果, 在真實(shí)項(xiàng)目的檢測測試上性能也超過了之前的模型. 該模型已開源(https://github.com/HuantWang/FUNDED_NISL).
Cheng等人[66]也利用圖來對代碼片段進(jìn)行表征, 其提出了DeepWukong. 具體地, 其首先生成代碼的控制依賴圖和數(shù)據(jù)依賴圖, 使用分析工具SVF從其中找到系統(tǒng)API調(diào)用作為關(guān)鍵節(jié)點(diǎn)并抽取切片, 使用Doc2Vec將清洗后的代碼轉(zhuǎn)化為向量形式, 將得到的切片圖向量表示投入3種圖卷積網(wǎng)絡(luò)(GCN、GAT、k-GNNs)進(jìn)行分類. 通過圖的形式, 既保留了結(jié)構(gòu)信息(邊)也保留了文本信息(節(jié)點(diǎn)向量). 在人工數(shù)據(jù)和真實(shí)數(shù)據(jù)的部分實(shí)驗(yàn)結(jié)果顯示: 不論使用哪種圖卷積網(wǎng)絡(luò), DeepWukong都能擁有較好的辨別性能. 該模型已開源(https://github.com/DeepWukong/DeepWukong).
總的來說, 基于圖的表征相對于序列或樹能夠顯式表征更多維度的代碼特征, 當(dāng)前被認(rèn)為是更具前景的代碼表征模式. 但基于圖的表征也存在一些問題, 例如在基于圖的表征模式下, 相同節(jié)點(diǎn)往往會(huì)被合并, 代碼語言的自然順序也會(huì)丟失, 這類信息丟失問題都是在構(gòu)建基于圖的表征時(shí)需要考慮的.
3.1.4
基于其他表征
除了采用序列、樹或圖的方式來對代碼進(jìn)行表征以外, 對代碼進(jìn)行其他形式的轉(zhuǎn)化也是一種思路.
Cao等人[32]提出了帶有傅里葉變換的深度卷積LSTM神經(jīng)網(wǎng)絡(luò)FTCLNet用于漏洞檢測. 具體地, 其使用離散傅里葉變換方法將代碼空間轉(zhuǎn)換為頻域, 并將卷積神經(jīng)網(wǎng)絡(luò)與長短期記憶網(wǎng)絡(luò)結(jié)合起來, 以捕捉頻域上的局部和全局特征, 再通過反向傅里葉變化將其轉(zhuǎn)化回代碼空間, 同時(shí)加入注意力機(jī)制來調(diào)整權(quán)重, 最后使用全連接層進(jìn)行預(yù)測. 實(shí)驗(yàn)結(jié)果顯示: FTCLNet的檢測效果高于VulDeePecker等深度方法, 并顯著高于Flawfinder等檢測工具.
對源代碼進(jìn)行分析, 涉及到路徑可達(dá)等問題, 這對模型的求解能力提出了很高的要求, 也影響了模型的性能. 一個(gè)解決方案是通過編譯, 借助編譯器將模型轉(zhuǎn)化為匯編代碼, 再交給深度學(xué)習(xí)進(jìn)行后續(xù)的缺陷判斷. Pechenkin等人[76]使用雙向LSTM對向量化的匯編代碼進(jìn)行缺陷判別. 匯編代碼的操作更加細(xì)化, 但同時(shí)會(huì)導(dǎo)致更大的代碼量, 使得對長程依賴的代碼結(jié)構(gòu)更加難以捕捉.
一些語言特性會(huì)導(dǎo)致直接對源代碼進(jìn)行缺陷檢測較為困難, 如C/C++中宏的跨文件使用. 這時(shí), 利用編譯器對源代碼進(jìn)行預(yù)處理可以減緩這些問題. Li等人[77]提出了VulDeeLocator, 其將源代碼轉(zhuǎn)化為中間代碼再進(jìn)行缺陷檢測, 并使用粒度細(xì)化來縮小定位的范圍. VulDeeLocator讀入中間代碼的向量表征與定位缺陷的矩陣表示, 其在標(biāo)準(zhǔn)的Bi-GRU模型中增加了3層: 通過乘法層完成注意力獲取; 通過k-max池化層與平均池化層來完成粒度細(xì)化. 在200個(gè)隨機(jī)挑選的真實(shí)工程文件中, VulDeeLocator檢測出了18個(gè)缺陷, 其中16個(gè)為已報(bào)出缺陷, 2個(gè)為靜默修復(fù)缺陷. 不過, 該模型并未開源. 此外, 將代碼轉(zhuǎn)化為中間語言需要對代碼進(jìn)行編譯, 這在大規(guī)模程序的應(yīng)用場景下成本較高, 其易用性低于直接針對源代碼進(jìn)行操作. 該模型已開源(https://github.com/VulDeeLocator/VulDeeLocator).
3.2
可解釋性
雖然在實(shí)驗(yàn)結(jié)果上, 基于深度學(xué)習(xí)的缺陷檢測已經(jīng)展現(xiàn)了較好的效果, 甚至能夠超過一些傳統(tǒng)的檢測方法, 但是深度學(xué)習(xí)方法只能提供結(jié)果, 而不能提供解釋性的指導(dǎo). 相比之下, 基于領(lǐng)域?qū)<揖帉懙穆┒礄z測規(guī)則得到的檢測結(jié)果能夠更好地提供這些解釋. 此外, 解釋性的缺失也使得從業(yè)人員無法判斷基于深度學(xué)習(xí)的缺陷檢測器學(xué)到了什么知識. 因此, 深度學(xué)習(xí)可解釋性是一個(gè)重要的研究課題, 它可以幫助人類深入了解軟件漏洞的起因、檢測, 并對缺陷的確認(rèn)與修復(fù)提供幫助.
An等人[78]認(rèn)為: 將函數(shù)或文件作為缺陷粒度過于寬泛, 其包含了過多的冗余信息. 而且即使判斷了包含缺陷后, 也需要花費(fèi)很多的人力去定位缺陷的具體位置. 因此, 切片才是合適的粒度, 且模型需要提供更多的可解釋性. 為此, 他們提出了AVDHRAM, 即基于層次表示和注意力機(jī)制的自動(dòng)缺陷檢測模型. 其將程序分為了5個(gè)層次, 分別是程序、函數(shù)、切片、語句、字符. 通過與SySeVR同樣的切片起始點(diǎn)開始切片, 在經(jīng)過符號化與向量化后, 通過使用層次注意力網(wǎng)絡(luò)(hierarchical attention network)來學(xué)習(xí)通過字符表示語句與通過語句表示切片. 其中, 注意力機(jī)制還可以用來進(jìn)行可視化的表示, 用以表明對模型判斷指導(dǎo)最多的部分, 從而輔助人工驗(yàn)證. 實(shí)驗(yàn)結(jié)果顯示: AVDHRAM的檢測效果顯著好于靜態(tài)分析工具, 與SySeVR性能相當(dāng).
Zou等人[79]也針對可解釋性作了一些初步的嘗試. 他們提出了一個(gè)可解釋框架, 以通過模型對代碼段的缺陷判斷抽取出判斷規(guī)則. 該框架的核心內(nèi)容是識別對做出特定預(yù)測貢獻(xiàn)最多的少量token, 通過這些token構(gòu)建一個(gè)決策樹規(guī)則, 從而幫助該領(lǐng)域人員的理解與判斷. 該框架應(yīng)用在VulDeePecker與SySeVR模型上的結(jié)果顯示: 該框架確實(shí)可以識別重要特征, 對人工驗(yàn)證檢測器的結(jié)果起到了輔助的作用. 但是, 該解釋性框架也存在一些問題, 例如: 無法解釋為什么模型認(rèn)為某些token的重要性更高; 生成的規(guī)則是半自動(dòng)化總結(jié)的, 而不是完全自動(dòng)化地進(jìn)行解釋; 框架針對每一個(gè)特別的預(yù)測進(jìn)行解釋規(guī)則的生成, 而不能生成適用于解釋其他示例的全局規(guī)則. 這些問題都是日后工作亟待解決的.
Mao等人[80]提出了一個(gè)基于注意力機(jī)制與雙向RNN的可解釋性缺陷檢測模型, 其首先將源代碼按照函數(shù)轉(zhuǎn)化為AST, 使用一個(gè)堆疊的雙向LSTM網(wǎng)絡(luò)來學(xué)習(xí)其表示, 再投入基于注意力機(jī)制的雙向RNN模型進(jìn)行分類. 在NVD與Sard抽取出的數(shù)據(jù)集測試下, 其獲得了較好的分類效果, 但是對于可解釋性的效果, 作者并未提出定量的評估方法.
為了使模型能夠更精細(xì)地告知代碼中哪些部分是與缺陷相關(guān)的, Li等人[81]提出了一個(gè)基于圖網(wǎng)絡(luò)的可解釋的缺陷檢測器IVDetect (interpretable vulnerability detector), 用來豐富模型的輸出內(nèi)容. 傳統(tǒng)方法會(huì)將缺陷函數(shù)的整體作為輸入, 而IVDetect會(huì)對其中語句進(jìn)行“缺陷相關(guān)”和“上下文”的區(qū)分. 其首先構(gòu)建缺陷判別模型FA-GCN, 將源代碼以程序依賴圖的形式輸入, 在編碼時(shí)加入其數(shù)據(jù)依賴與控制依賴上下文; 分類主體是用于圖分類的圖卷積網(wǎng)絡(luò)GCN, 并使用了特征注意力機(jī)制. IVDetect使用GNNExplainer來提供解釋性結(jié)果, 其將FA-GNN模型、其判斷結(jié)果和函數(shù)PDG作為輸入, 通過在PDG中尋找一個(gè)最小子圖, 使其在FA-GNN中得到的分?jǐn)?shù)最接近原PDG. GNNExplainer通過對邊進(jìn)行遮蓋并觀察模型判斷來達(dá)到對邊重要性的評估. 實(shí)驗(yàn)結(jié)果顯示: 在函數(shù)級缺陷檢測上, IVDetect相對前人方法有大幅度的提升; 在缺陷相關(guān)語句的辨別中, IVDetect有67%可以在TOP 5列表中準(zhǔn)確命中.
該模型已開源(https://github.com/vulnerabilitydetection/VulnerabilityDetectionResearch).
但是對于可解釋性問題, 最大的難點(diǎn)在于難以定量評估其解釋性效果. Li等人[81]使用了Reveal[26]、Fan[52]、Devign[65]的數(shù)據(jù)集, 均為函數(shù)級缺陷代碼數(shù)據(jù)集. 共包含197 551個(gè)函數(shù), 其中, 22 278個(gè)為缺陷函數(shù), 占比11.3%. 其中, Fan數(shù)據(jù)集中包括對缺陷修復(fù)的記錄, 因此被用于評估缺陷相關(guān)語句的判斷效果. 但是, 修復(fù)語句與缺陷相關(guān)語句并不等價(jià), 簡單地將修復(fù)所影響的語句作為解釋性語句的標(biāo)準(zhǔn)答案, 合理性不高.
事實(shí)上, 相較于缺陷檢測中的標(biāo)準(zhǔn)答案, 可解釋性由于其具備一定的主觀因素, 其標(biāo)準(zhǔn)答案的制訂更加困難. 因此, 為了評估可解釋性的優(yōu)劣, 還需要一個(gè)能夠被廣泛接受的評價(jià)標(biāo)準(zhǔn).
3.3
泛化能力
在缺陷檢測的過程中, 不同項(xiàng)目之間或不同語言之間的缺陷存在分布上的差異, 因此, 基于深度學(xué)習(xí)的方法需要使用域適應(yīng)學(xué)習(xí)的方法來使得模型具備跨項(xiàng)目與跨語言的泛化能力. 深度域適應(yīng)學(xué)習(xí)鼓勵(lì)模型學(xué)習(xí)源數(shù)據(jù)和目標(biāo)數(shù)據(jù)的新表示, 以最大限度地縮小它們之間的差異. 源數(shù)據(jù)和目標(biāo)數(shù)據(jù)通過生成器映射到聯(lián)合特征空間, 通過最小化其分布之間的差異, 使得兩者在聯(lián)合空間中得以更好地鏈接.
Nguyen等人[82]利用深度領(lǐng)域適應(yīng)來進(jìn)行缺陷檢測, 提出了CDAN (code domain adaptation network)模型, 其使用序列代碼的向量表示作為輸入, 通過雙向RNN作為生成器來生成源數(shù)據(jù)和目標(biāo)數(shù)據(jù)在聯(lián)合空間中的表示, 通過判別器對兩者表示進(jìn)行區(qū)分, 以不斷地減少兩者表示的差距, 最終通過在有標(biāo)簽源數(shù)據(jù)上訓(xùn)練的分類器進(jìn)行分類. 由于在納什均衡點(diǎn), 源與目標(biāo)在聯(lián)合空間中是相同的, 因此可以將訓(xùn)練好的分類器對目標(biāo)進(jìn)行預(yù)測. 在CDAN基礎(chǔ)上, 其提出了半監(jiān)督的模型SCDAN (semi-supervised code domain adaptation network), 使用條件交叉熵和光譜圖使其滿足平滑假設(shè)和聚類假設(shè). 實(shí)驗(yàn)結(jié)果顯示: 使用CDAN遷移框架, 能夠顯著提高模型在未標(biāo)注數(shù)據(jù)上的預(yù)測性能.
當(dāng)前, 深度學(xué)習(xí)模型在缺陷檢測任務(wù)方面能夠取得較好的效果, 但其訓(xùn)練集和測試集是同分布的. 事實(shí)上, 當(dāng)應(yīng)用到實(shí)際項(xiàng)目中時(shí), 待測樣本往往與訓(xùn)練樣本是不同分布的. 例如待測樣本和訓(xùn)練樣本來源于不同的工程, 或者是不同的缺陷類型. 為此, Liu等人[48]提出了CD-VulD, 即跨域軟件缺陷檢測, 以解決缺陷預(yù)測模型的跨域遷移問題. 具體地, CD-VulD首先將程序轉(zhuǎn)化為token序列并轉(zhuǎn)化為數(shù)字型向量, 然后通過基于Bi-LSTM的深度特征模型來學(xué)習(xí)高層序列表示, 通過矩陣轉(zhuǎn)移學(xué)習(xí)框架來縮小源域和目標(biāo)域的分布差異以學(xué)習(xí)跨域表示, 最終學(xué)到的跨域表示被用來訓(xùn)練分類器進(jìn)行分類. 該模型針對的是函數(shù)級缺陷檢測. 實(shí)驗(yàn)結(jié)果顯示, 使用跨域?qū)W習(xí)得到的代碼表示能夠顯著提高機(jī)器學(xué)習(xí)和深度學(xué)習(xí)分類器的檢測效果. 在跨域問題上, CD-VulD在類型上的遷移和項(xiàng)目間的遷移都顯示出明顯優(yōu)勢, 這種優(yōu)勢在源域與目標(biāo)域使用不同代碼表征方式時(shí)依然存在甚至更加突出. 該模型并未開源.
上述研究主要通過遷移方法提高項(xiàng)目間的泛化能力, 而語言之間的泛化與遷移同樣應(yīng)予以重視.
Hua等人[83]復(fù)現(xiàn)了針對C/C++語言的缺陷檢測系統(tǒng)VulDeePecker與SySeVR, 以測試其對Java代碼中相對較多的單語句缺陷的檢測效果. 其在單語句缺陷數(shù)據(jù)集ManySStuBs4J上的檢測準(zhǔn)確度從原來的超過90%降低到70%. 這印證了單語句缺陷并不能很好地被通用缺陷檢測系統(tǒng)所探查.
事實(shí)上, 語言間的泛化是一個(gè)同樣重要且難度更大的研究點(diǎn).
3.4
額外特征的挖掘
在缺陷檢測的任務(wù)背景下, 除了代碼段本身的特征, 還包含一些額外的特征, 例如代碼的傳統(tǒng)度量信息、缺陷的修復(fù)信息, 這些都可以為模型的特征挖掘提供指導(dǎo).
缺陷代碼和非缺陷代碼的差異有時(shí)候很小, 有時(shí)甚至修改單個(gè)變量、符號甚至數(shù)值就可以改變代碼的正確性. 而基于相似度的缺陷復(fù)用檢測往往無法分辨該類細(xì)微的差異而產(chǎn)生誤報(bào). 因此, 重點(diǎn)關(guān)注缺陷代碼及其修復(fù)是十分有意義的.
在機(jī)器學(xué)習(xí)的缺陷檢測研究中, Xiao等人[45]就將代碼的修復(fù)信息作為重要特征來挖掘. 他們提出了MVP模型. 首先對缺陷代碼及其對應(yīng)的修復(fù)版本生成抽象語法樹與代碼屬性圖, 根據(jù)補(bǔ)丁的修改情況, 使用不同策略進(jìn)行切片, 以分離出缺陷相關(guān)的語法與語義特征, 然后通過待測代碼的特征與其比對, 若其匹配缺陷特征而不匹配修復(fù)特征, 則認(rèn)為其有缺陷. MVP在10個(gè)開源工程上的檢測效果顯著高于基于克隆(ReDeBug、VUUDY)、基于函數(shù)匹配(SourcererCC、CCAligner)、基于深度學(xué)習(xí)(VulDeePecker、Devign)的檢測方法, 同時(shí), 其性能高于商業(yè)分析工具(Coverity、Checkmarx), 擁有更低的誤報(bào)率和漏報(bào)率. 不過, 該模型并未開源.
Wu等人[84]同樣利用了修復(fù)信息來降低誤報(bào)率, 不同的是, 其只是簡單地通過相似度來進(jìn)行計(jì)算, 若待測代碼和匹配缺陷的修復(fù)后版本相似度更高, 則認(rèn)定該報(bào)出為誤報(bào).
在深度學(xué)習(xí)的缺陷檢測研究中, 也應(yīng)該重點(diǎn)關(guān)注如何更好地利用缺陷的修復(fù)信息.
使用深度學(xué)習(xí)進(jìn)行缺陷檢測, 并不一定要完全拋棄傳統(tǒng)方法, 也可以進(jìn)行一定的結(jié)合.
Clemente等人[50]利用多層前饋神經(jīng)網(wǎng)絡(luò)來尋找適用于缺陷檢測的代碼度量組合. 其計(jì)算了代碼的3個(gè)維度的度量值, 包括復(fù)雜度度量、組成數(shù)值度量、面向?qū)ο蠖攘? 并輸入多層前饋神經(jīng)網(wǎng)絡(luò)來尋找合適的組合.實(shí)驗(yàn)結(jié)果顯示: 使用深度網(wǎng)絡(luò)來結(jié)合傳統(tǒng)度量值是有效果的, 且其效果要好于使用機(jī)器學(xué)習(xí)(對比決策樹、隨機(jī)森林、支持向量機(jī)、樸素貝葉斯), 但提升效果有限.
傳統(tǒng)方法通過代碼的度量信息來進(jìn)行缺陷預(yù)測, 但是相對于缺陷模式的多樣性, 通過度量進(jìn)行表征還不夠充分. Zhang等人[54]提出了DefectLearner, 其在傳統(tǒng)代碼度量中加入了交叉熵(cross entropy)作為代碼特征, 一同投入深度網(wǎng)絡(luò)進(jìn)行缺陷檢測. DefectLearner首先對代碼進(jìn)行序列化的向量表示, 使用LSTM構(gòu)造語言模型來捕捉代碼模式與隱層特征, 最后加入標(biāo)簽信息與交叉熵及度量特征來訓(xùn)練分類器. 該模型使用了支持向量機(jī)、隨機(jī)森林、樸素貝葉斯與邏輯回歸這4種分類器. 實(shí)驗(yàn)結(jié)果顯示: 交叉熵的判別效果可以高于一半的傳統(tǒng)度量值, 在加入交叉熵特征后, 能夠全面提高模型的檢測性能.
傳統(tǒng)的缺陷檢測方法在一定程度上是有效果的, 這些效果在實(shí)際的工業(yè)領(lǐng)域也已經(jīng)得到了驗(yàn)證. 但是傳統(tǒng)方法往往針對的是不同的使用場景, 在不同類型上的檢測水平存在差異. 為此, Jabeen等人[85]提出了一個(gè)整合的缺陷檢測模型, 以對傳統(tǒng)檢測方法加以綜合考慮. 該模型選擇了4個(gè)傳統(tǒng)缺陷檢測模型, 將其檢測結(jié)果作為輸入, 投入多層感知機(jī)(MLP)以獲得整合后的缺陷預(yù)測結(jié)果. 其使用的是傳統(tǒng)的3層感知機(jī)(輸入層、隱層、輸出層), 沒有作特殊的修改. 在從CVE抽取出的真實(shí)用例作為數(shù)據(jù)集的實(shí)驗(yàn)結(jié)果上看, 使用MLP進(jìn)行整合能夠獲得最低的錯(cuò)誤率.
就當(dāng)前缺陷檢測商業(yè)軟件的發(fā)展情況來看, 絕大多數(shù)商業(yè)軟件還是基于傳統(tǒng)的規(guī)則方法. 這是由于基于規(guī)則的方法往往能夠提供完整的缺陷路徑, 對于其后續(xù)的確認(rèn)更為方便, 且當(dāng)前基于規(guī)則的方法檢測效果更為穩(wěn)定, 不需要考慮跨域遷移等問題. 這種商業(yè)現(xiàn)象顯示出了傳統(tǒng)方法在當(dāng)今的缺陷檢測領(lǐng)域依然存在其價(jià)值. 因此, 如何將深度學(xué)習(xí)技術(shù)與傳統(tǒng)方法相結(jié)合, 是一個(gè)值得探究的研究點(diǎn).
3.5
當(dāng)前深度學(xué)習(xí)模型存在的問題
為了便于對比, 我們對第3節(jié)中梳理的深度學(xué)習(xí)模型進(jìn)行列表展示, 對于每一種代碼表征形式挑選至多3項(xiàng)代表性工作, 詳細(xì)列舉其各項(xiàng)技術(shù)信息. 如表 3所示, 表中的每一行都代表一項(xiàng)研究工作. 第1列代表了該研究使用的代碼表征形式. 第3列為分析對象的編程語言. 第4列為分析對象的樣本粒度. 第5列為分析對象表征時(shí)選擇的特征, 包括抽象語法樹(AST)、控制流圖(CFG)、數(shù)據(jù)流圖(DFG)、程序依賴圖(PDG)、代碼屬性圖(CPG)、離散傅里葉變換(DFT)、編譯中間代碼(LLVM)等. 第6列為該深度模型使用的模型架構(gòu), 包括前饋神經(jīng)網(wǎng)絡(luò)(FNN)、卷積神經(jīng)網(wǎng)絡(luò)(CNN)、雙向長短期記憶(bi-LSTM)、雙向門控循環(huán)單元(bi-GRU)等. 第7列為該模型所使用的評價(jià)指標(biāo), F1(以及多分類下的W-F1)即指代包含誤報(bào)率(FPR)、漏報(bào)率(FNR)、召回率(TPR/recall)、精確率(P)和F1值的傳統(tǒng)評價(jià)體系, 其他指標(biāo)還包括正確率(accuracy)等. 第8列標(biāo)記其是否開源. 第9列表示該類表征的預(yù)處理難度.

表 3 深度學(xué)習(xí)模型統(tǒng)計(jì)信息小結(jié)
可以看到: 針對不同的語言, 研究者們已經(jīng)嘗試使用了主流的卷積、序列、圖模型進(jìn)行缺陷檢測任務(wù), 主要檢測對象集中在主流編程語言. 但各模型針對的樣本粒度差異較大, 且只有個(gè)別模型為開源狀態(tài), 使得模型間的比較較為困難.
從代碼表征維度上看, 基于序列的表征較為直觀, 且不需要對待測代碼進(jìn)行額外的分析處理, 在實(shí)現(xiàn)上較為簡便. 但是代碼語言具有較強(qiáng)的結(jié)構(gòu)性與局部性, 其上下文的依賴關(guān)系復(fù)雜且距離較長, 因此, 單純地使用序列作為代碼表征會(huì)損失大量的代碼結(jié)構(gòu)特征. 基于樹的表征可以更好地顯式表征代碼中的結(jié)構(gòu)信息, 但事實(shí)上, 除了抽象語法樹能夠表示的結(jié)構(gòu)信息以外, 源代碼本身還具備數(shù)據(jù)流、控制流等多種不同維度的特征, 而這些特征無法顯式地被抽象語法樹表示. 基于圖的表征能夠顯式表征更多形式與維度的代碼特征, 當(dāng)前被認(rèn)為是更具前景的代碼表征模式. 但基于圖的表征也存在一些問題, 例如: 在基于圖的表征模式下, 相同節(jié)點(diǎn)往往會(huì)被合并, 代碼語言的自然順序也會(huì)丟失; 其次, 大規(guī)模代碼檢測時(shí)的圖構(gòu)建需要耗費(fèi)大量的計(jì)算資源與時(shí)間, 這些都是在使用基于圖的表征時(shí)需要考慮的.
除了代碼的表征, 在模型階段對數(shù)據(jù)集的劃分、使用與針對性設(shè)計(jì)是更加突出的問題.
3.5.1
多數(shù)據(jù)來源混用
在前述方法中, 許多研究[42?44]都使用了多來源的數(shù)據(jù)集, 作為訓(xùn)練和評估的基礎(chǔ). 多來源數(shù)據(jù)集往往是人工構(gòu)造的數(shù)據(jù)集Sard與從真實(shí)項(xiàng)目中抽取的缺陷條目(NVD抽取), 而由于真實(shí)項(xiàng)目缺陷條目獲取成本較高, 這類混合數(shù)據(jù)集大多只包含少量的真實(shí)缺陷. 例如, VulDeePecker[42]的數(shù)據(jù)集中僅有1.4% (840個(gè))來自于真實(shí)項(xiàng)目缺陷(NVD), 這種數(shù)據(jù)比例會(huì)導(dǎo)致基于大量人工構(gòu)造缺陷數(shù)據(jù)訓(xùn)練的深度模型在真實(shí)缺陷上的檢測能力并沒有得到很好的評估.
事實(shí)上, 人工構(gòu)造缺陷在代碼長度與復(fù)雜度上都遠(yuǎn)低于真實(shí)抽取的缺陷, 人工構(gòu)造缺陷上挖掘得到的特征可能并不適用于真實(shí)缺陷. 這需要更進(jìn)一步的探究.
3.5.2
重復(fù)切片導(dǎo)致的數(shù)據(jù)泄露
表 4為VulDeePecker[42]構(gòu)建的數(shù)據(jù)集中的兩個(gè)樣本, 其切片代碼與標(biāo)簽完全一致. 由于在一個(gè)切片中的不同位置作為起點(diǎn)進(jìn)行切片, 可能會(huì)得到一樣的切片, 因此會(huì)導(dǎo)致數(shù)據(jù)重復(fù). 而當(dāng)前劃分?jǐn)?shù)據(jù)集時(shí)大多使用隨機(jī)劃分, 會(huì)使得這些重復(fù)的數(shù)據(jù)分別被劃分到訓(xùn)練集與測試集, 這就導(dǎo)致了大量的泄露, 使得模型的檢測效果虛高.

表 4 VulDeePecker[42]數(shù)據(jù)集中的兩個(gè)樣本
事實(shí)上, 從不同位置作切片生成相同的切片符合實(shí)際應(yīng)用的樣本分布. 因此, 解決該問題不應(yīng)從去重的角度, 而應(yīng)從訓(xùn)練數(shù)據(jù)的劃分角度來考慮. 需要在劃分時(shí)避免泄露, 即避免相同的切片被分開, 即可規(guī)避重復(fù)切片帶來的虛假測試值.
3.5.3
缺乏數(shù)據(jù)不平衡的針對性設(shè)計(jì)
由于代碼中大部分代碼均為正確代碼, 因此在正常的構(gòu)造流程下, 缺陷代碼在其中的比例都較低. 例如在VulDeePecker[42]中, 缺陷代碼只占28.8%. 因此, 在這種條件下, 需要針對不平衡問題進(jìn)行針對性的設(shè)計(jì).
已有部分研究考慮到該問題, 并通過例如SMOTE算法進(jìn)行改進(jìn). 不過, 該方向依然存在較大改進(jìn)的空間, 例如可以探究使用數(shù)據(jù)增強(qiáng)的方式改善不平穩(wěn)問題.
3.5.4
評價(jià)指標(biāo)不符合使用場景
當(dāng)前, 絕大多數(shù)缺陷檢測系統(tǒng)均使用基于F1值的評價(jià)體系, 即分別計(jì)算準(zhǔn)確率(accuracy)、精確率(precision)、召回率(recall), 最后通過F1值綜合評價(jià)模型性能. 一些研究也會(huì)使用真正例(TP)、假正例(FP)、假反例(FN)和真反例(TN)來評估. 這些均為較常用的評估指標(biāo), 這里不再贅述.
然而, F1值無法很好地評價(jià)真實(shí)使用場景. 在真實(shí)開發(fā)環(huán)境中, 人工審查往往精力有限, 不會(huì)審查全部報(bào)出缺陷, 而會(huì)根據(jù)系統(tǒng)預(yù)測的排序, 審查靠前的報(bào)出. 因此, 應(yīng)當(dāng)加入TOP N限制下的各項(xiàng)指標(biāo)來評估, 其更加符合實(shí)際的應(yīng)用場景.
4 未來研究展望
在對當(dāng)前研究進(jìn)展進(jìn)行了歸納總結(jié)與問題闡述后, 我們對該任務(wù)未來的研究點(diǎn)進(jìn)行展望.
4.1
構(gòu)建通用多粒度數(shù)據(jù)集
當(dāng)前, 缺陷檢測領(lǐng)域沒有一個(gè)統(tǒng)一通用的評價(jià)標(biāo)準(zhǔn)與評價(jià)流程, 這使得不同模型之間的比對較為不便.
如前文所述, 當(dāng)前研究均使用自行構(gòu)建的缺陷代碼數(shù)據(jù)集, 這些數(shù)據(jù)集在數(shù)據(jù)來源、數(shù)據(jù)粒度與標(biāo)注方式上均存在較大的差異.
從數(shù)據(jù)來源上看, 不同的數(shù)據(jù)來源意味著其樣本復(fù)雜程度的不同. 缺陷庫抽取數(shù)據(jù)(如NVD)來源于真實(shí)的工業(yè)代碼, 其復(fù)雜程度較高, 且模塊化程度高, 各組件之間的依賴關(guān)系與調(diào)用關(guān)系復(fù)雜. 人工構(gòu)造數(shù)據(jù)(如Sard)來源于人工撰寫的測試用例, 其復(fù)雜程度低, 且主要針對缺陷的表示, 而大多忽略其真實(shí)的功能, 因此為獨(dú)立程序片段, 幾乎沒有組件之間的長程依賴與復(fù)雜的調(diào)用關(guān)系. 在這兩類不同復(fù)雜度的數(shù)據(jù)來源中抽取的缺陷數(shù)據(jù), 其對代碼缺陷的表征能力差距較大, 因此不適合從數(shù)值(例如F1等)上進(jìn)行橫向比較. 從實(shí)際應(yīng)用的角度來看, 缺陷檢測系統(tǒng)需要具備對真實(shí)工業(yè)代碼的檢測能力, 即理想的缺陷代碼數(shù)據(jù)集應(yīng)來源于NVD等工業(yè)代碼而非人工撰寫的測試用例. 但工業(yè)代碼缺陷數(shù)據(jù)的獲取難度與成本遠(yuǎn)大于測試用例, 需要更加完善的樣本提取技術(shù)與大量不可避免的人工審查, 這可能需要相關(guān)領(lǐng)域的研究者共同努力.
從數(shù)據(jù)粒度上看, 不同的數(shù)據(jù)粒度之間難以進(jìn)行統(tǒng)一評價(jià). 當(dāng)前, 缺陷代碼數(shù)據(jù)集沒有一個(gè)統(tǒng)一的數(shù)據(jù)粒度, 在文件級數(shù)據(jù)粒度過大成為共識后, 當(dāng)前研究主要使用函數(shù)級數(shù)據(jù)與切片級數(shù)據(jù). 然而如第2.2.3節(jié)所述, 即使是由同一個(gè)缺陷條目構(gòu)造的函數(shù)級數(shù)據(jù)與切片級數(shù)據(jù), 因其代碼切割與分離方式的不同, 也無法進(jìn)行橫向的比較. 因此, 必須明確統(tǒng)一的數(shù)據(jù)粒度, 才能保證數(shù)值比較的公平性. 函數(shù)級數(shù)據(jù)在劃分時(shí)成本極低, 且在檢測過程中不需要對被測代碼進(jìn)行分析(切割為函數(shù)即可). 而切片級數(shù)據(jù)需要在構(gòu)建數(shù)據(jù)集與檢測被測代碼時(shí)均對代碼進(jìn)行數(shù)據(jù)流、控制流等分析, 對資源的需求較大, 時(shí)間成本也較高. 然而, 函數(shù)級數(shù)據(jù)基于的樸素假設(shè)是: 缺陷發(fā)生在函數(shù)的范圍內(nèi). 這在大規(guī)模工業(yè)代碼中顯然是難以支持的, 特別是在模塊化的情況下, 數(shù)據(jù)的聲明與使用往往不存在于單一函數(shù)中. 因此, 代碼切片應(yīng)該是更為合理的數(shù)據(jù)粒度, 可以更加完整地表征缺陷的流程.
從標(biāo)注方式上看, 不同的標(biāo)注方式使得標(biāo)簽的正確性存在差異. 安全相關(guān)人員的人工標(biāo)注能夠保證標(biāo)簽的質(zhì)量, 但其獲取成本較高. 為了解決這一問題, 許多研究者嘗試使用啟發(fā)式方法、自動(dòng)化方法快速地進(jìn)行標(biāo)注. 然而就目前的研究情況看, 自動(dòng)化與啟發(fā)式方法均難以達(dá)到理想的標(biāo)注效果. 因此在現(xiàn)階段, 使用人工標(biāo)注來構(gòu)造通用數(shù)據(jù)集是無法避免的.
針對傳統(tǒng)缺陷檢測方法的統(tǒng)一評測, 有研究者進(jìn)行了嘗試. Zhang等人[86]提出了iTES, 其首先自動(dòng)構(gòu)建了一個(gè)缺陷代碼庫, 通過控制模塊選擇測試使用的條目供被測系統(tǒng)檢測, 通過監(jiān)控模塊記錄測試結(jié)果并通過評估模塊對各項(xiàng)測試數(shù)據(jù)進(jìn)行生成. iTES最終會(huì)對檢測系統(tǒng)的報(bào)出數(shù)目、誤報(bào)率、召回率、資源使用、分析時(shí)間和關(guān)鍵程度進(jìn)行評估.
該系統(tǒng)是針對靜態(tài)與動(dòng)態(tài)缺陷檢測系統(tǒng)設(shè)計(jì)的, 其只依靠源代碼即可進(jìn)行檢測. 而基于深度學(xué)習(xí)的缺陷檢測系統(tǒng)在測試上涉及到不同的輸入粒度(如各類屬性圖、切片等), 需要對源代碼進(jìn)行較多的預(yù)處理操作, 因此還需針對該類問題進(jìn)行針對性的設(shè)計(jì).
經(jīng)過上述分析, 對于通用的缺陷代碼數(shù)據(jù)集, 我們認(rèn)為其應(yīng)該來源于真實(shí)的工業(yè)軟件代碼, 使用切片對缺陷路徑進(jìn)行分離, 通過足量的人工審查進(jìn)行標(biāo)注, 并進(jìn)行充分的多粒度預(yù)處理操作. 這些步驟都具有較高的成本, 需要該領(lǐng)域研究者的共同努力.
4.2
利用無標(biāo)記數(shù)據(jù)
當(dāng)前, 使用深度學(xué)習(xí)方法來進(jìn)行缺陷檢測, 絕大多數(shù)都遵循著傳統(tǒng)的“l(fā)earn-from-bugs”流程, 即先構(gòu)造帶標(biāo)簽的缺陷代碼數(shù)據(jù)集, 再搭建深度神經(jīng)網(wǎng)絡(luò)來挖掘并學(xué)習(xí)數(shù)據(jù)集中的特征. 因此, 神經(jīng)網(wǎng)絡(luò)的缺陷檢測能力極大程度上會(huì)受到數(shù)據(jù)集質(zhì)量的影響. 這就意味著需要大量的標(biāo)注數(shù)據(jù)來訓(xùn)練神經(jīng)網(wǎng)絡(luò). 然而, 有別于其他深度學(xué)習(xí)任務(wù)(例如圖像識別)可以較低成本地獲得標(biāo)注數(shù)據(jù), 缺陷代碼的數(shù)據(jù)標(biāo)注需要較好的代碼相關(guān)知識, 因此其必須由專業(yè)的從業(yè)人員完成, 導(dǎo)致其樣本獲得成本較高.
此外, 通過標(biāo)注的缺陷代碼數(shù)據(jù)集訓(xùn)練得到的深度學(xué)習(xí)模型, 只能針對數(shù)據(jù)集擁有的缺陷類型進(jìn)行檢測, 若要對檢測缺陷類型進(jìn)行擴(kuò)展, 則必須增加大量的新類型標(biāo)注數(shù)據(jù), 擴(kuò)展能力有限.
然而, 在日漸龐大的開源代碼庫中, 有海量無標(biāo)簽的代碼資源. 因此, 如何利用海量未標(biāo)記數(shù)據(jù), 是一個(gè)重要的研究點(diǎn).
Ahmadi等人[87]使用非學(xué)習(xí)的方法, 在無標(biāo)簽的代碼中通過2次聚類, 先找到功能相近的代碼, 再從中找到類內(nèi)有差異的代碼, 通過“大部分代碼是無缺陷”的假設(shè), 將聚類中有差異的代碼標(biāo)記為缺陷代碼, 即不需要額外信息即可自動(dòng)完成缺陷數(shù)據(jù)的標(biāo)注.
在深度學(xué)習(xí)的框架下, 同樣可以利用相似思路, 對無標(biāo)簽的數(shù)據(jù)加以表示與利用.
為了應(yīng)對標(biāo)注的缺陷數(shù)據(jù)較少的問題, Allamanis等人[38]提出了一種自監(jiān)督的缺陷檢測模型. 其使用一個(gè)選擇器對正確代碼進(jìn)行變異, 再通過一個(gè)檢測器對變異的位置與類型進(jìn)行判斷, 通過對抗的方式使得檢測器能夠具備檢測困難缺陷的能力. 由于其變異模式只有4種, 因此當(dāng)檢測器預(yù)測出缺陷模式后, 即可通過逆向變異完成對該缺陷的修復(fù). 但有限的變異模式也導(dǎo)致了該方法在缺陷類型上的泛化能力有限. 在針對真實(shí)項(xiàng)目的檢測中, 該方法報(bào)出了19個(gè)真實(shí)缺陷, 然而其誤報(bào)率高達(dá)98%, 在實(shí)用性上還有很大差距. 這同時(shí)也證實(shí)了使用人工變異構(gòu)造的缺陷數(shù)據(jù)難以匹配真實(shí)缺陷的復(fù)雜度. 該模型已開源(https://github.com/microsoft/neurips21-self-supervised-bug-detection-and-repair).
除此之外, 語言模型近年來在自然語言處理領(lǐng)域展現(xiàn)出的強(qiáng)大能力, 也為無監(jiān)督挖掘數(shù)據(jù)特征提供了新的思路. 當(dāng)前已有一些研究者在探究代碼語言模型的構(gòu)建與應(yīng)用, 如CodeBER[71]與CuBERT[88]. 此類代碼語言模型在代碼的簡單缺陷(如變量誤用)與錯(cuò)誤檢測上具有一定的效果, 但在復(fù)雜缺陷檢測任務(wù)下能力有限[88].因此, 如何構(gòu)建適用于缺陷檢測任務(wù)的代碼語言模型, 還需要進(jìn)一步的探究.
當(dāng)前已有較多的無監(jiān)督、半監(jiān)督方法被應(yīng)用在自然語言處理領(lǐng)域并取得了不錯(cuò)的效果. 將無監(jiān)督、半監(jiān)督方法應(yīng)用在缺陷檢測領(lǐng)域, 可以極大地解決標(biāo)注數(shù)據(jù)獲取成本高的問題.
4.3
明確深度學(xué)習(xí)能力邊界
代碼缺陷的類型眾多, 以CWE分類標(biāo)準(zhǔn)為例, 其將缺陷分為了10個(gè)大類, 其中的二級分類就有上百種之多, 這些不同的缺陷類型所擁有的特征和模式也是千差萬別的. 傳統(tǒng)的缺陷檢測方法會(huì)對每一個(gè)缺陷類型有針對性地設(shè)計(jì)缺陷規(guī)則, 而當(dāng)前的深度學(xué)習(xí)缺陷檢測方法沒有對其類型間差異的問題進(jìn)行處理, 大多簡單地將其按照二分類或多分類任務(wù)對待. 從缺陷原理上看, 其不同大類與小類在難易程度、復(fù)雜程度上存在較大的差異. 因此, 深度學(xué)習(xí)在不同缺陷類型上的效果, 即哪些缺陷類型適合使用深度學(xué)習(xí)方法, 是值得探究并明確的.
同時(shí), 由于不同的缺陷類型在缺陷原理上的差異, 可能適合不同的深度網(wǎng)絡(luò)機(jī)構(gòu)對其進(jìn)行挖掘. 因此, 對單一缺陷類型適合何種深度網(wǎng)絡(luò), 也是一個(gè)值得探究的研究點(diǎn).
Yuan等人[89]對基礎(chǔ)的深度學(xué)習(xí)模型進(jìn)行了初步的評估嘗試, 他們在3個(gè)項(xiàng)目的數(shù)據(jù)下比較了GRU、bi- GRU、DNN、LSTM這4種模型, 并對其訓(xùn)練效率進(jìn)行了比對. 從訓(xùn)練效率上看, DNN顯著優(yōu)于其他幾種序列模型. 但是該研究只在準(zhǔn)確度(accuracy)上進(jìn)行了測試, 由于數(shù)據(jù)集中正負(fù)樣本不平衡問題較為嚴(yán)重, 該度量值并不能充分反映模型的判斷能力. 對于模型的適用性還需要更加細(xì)致、全面的評估.
當(dāng)前對缺陷檢測的研究中, 從原始的完整源代碼到最后抽取出的缺陷片段與判斷結(jié)果, 中間的各個(gè)步驟都可以使用人工審查、傳統(tǒng)規(guī)則與深度學(xué)習(xí)的方法進(jìn)行. 例如, 當(dāng)前有探究使用深度學(xué)習(xí)來輔助SMT求解的研究工作, 雖然使用少量數(shù)據(jù)訓(xùn)練來獲得精準(zhǔn)的SMT求解能力是非常困難的, 但是利用深度學(xué)習(xí)對中間步驟進(jìn)行篩選和排序, 可以提高SMT求解的效率. 同理, 在缺陷檢測的任務(wù)背景下, 應(yīng)當(dāng)從應(yīng)用的角度出發(fā), 即從大規(guī)模工程的檢測角度出發(fā), 綜合地考慮與比對適合每個(gè)步驟使用的技術(shù), 而不是僅僅將缺陷檢測當(dāng)作一個(gè)獨(dú)立的分類任務(wù).
4.4
大規(guī)模工程的檢測
當(dāng)前, 對深度學(xué)習(xí)在源代碼缺陷檢測領(lǐng)域的研究大多停留在學(xué)術(shù)探究階段, 往往只將其當(dāng)作一項(xiàng)獨(dú)立的分類任務(wù), 即對數(shù)據(jù)集中的條目進(jìn)行分類. 事實(shí)上, 源代碼缺陷檢測作為軟件開發(fā)過程中重要的一環(huán), 具有較大的實(shí)際應(yīng)用意義. 因此, 同樣需要從工業(yè)應(yīng)用的視角對待該項(xiàng)研究, 從工業(yè)視角的大規(guī)模工程的檢測角度出發(fā), 其要保證流程的完整性與方法的可用性.
流程的完整性, 即從原始的全部工程代碼到抽取待測片段, 到模型生成缺陷判斷結(jié)果, 中間的各個(gè)步驟均可以使用人工審查、傳統(tǒng)規(guī)則與深度學(xué)習(xí)的方法進(jìn)行. 需要綜合地考慮與對比適合每個(gè)步驟使用的技術(shù).
而方法的可用性, 則對整套流程的效率提出了要求.
當(dāng)前的相關(guān)研究往往忽略了以上兩點(diǎn). 例如: 使用圖神經(jīng)網(wǎng)絡(luò)對經(jīng)過預(yù)處理的代碼屬性融合圖進(jìn)行分類能夠取得較好的數(shù)值效果, 但在實(shí)際的大規(guī)模工程檢測任務(wù)中, 對百萬行的工程代碼進(jìn)行代碼屬性融合圖的構(gòu)造會(huì)耗費(fèi)極大的計(jì)算資源與時(shí)間. 因此在后續(xù)的研究中, 如何適配大規(guī)模工程的實(shí)際檢測場景, 是一個(gè)需要重點(diǎn)關(guān)注的研究點(diǎn).
5 總結(jié)
基于深度學(xué)習(xí)進(jìn)行源代碼缺陷檢測利用了深度神經(jīng)網(wǎng)絡(luò)自動(dòng)挖掘深層特征的能力, 將安全開發(fā)者從繁重的規(guī)則編寫與特征工程中解脫出來, 因此也受到越來越多的關(guān)注. 本文針對該領(lǐng)域近5年的論文發(fā)表情況進(jìn)行了詳細(xì)的分析, 從數(shù)據(jù)集構(gòu)建與深度模型這兩個(gè)方面對當(dāng)前的技術(shù)進(jìn)行了分類與總結(jié), 并對面臨的挑戰(zhàn)與未來可能的研究重點(diǎn)進(jìn)行了闡述.
在大量研究者的探究與實(shí)驗(yàn)下, 深度學(xué)習(xí)對于缺陷檢測任務(wù)的能力已經(jīng)得到了驗(yàn)證, 深度學(xué)習(xí)對挖掘代碼中語義與結(jié)構(gòu)信息的能力相對傳統(tǒng)方法存在其優(yōu)勢. 但是需要看到的是: 深度學(xué)習(xí)在缺陷檢測方向上的應(yīng)用歷史較短, 當(dāng)前依然存在較多基礎(chǔ)性問題亟待解決, 在數(shù)據(jù)集與模型層面都有其改進(jìn)的方向. 特別是在通用數(shù)據(jù)集的建設(shè)上, 期待能有更多的研究人員共同努力, 為該領(lǐng)域的未來發(fā)展構(gòu)建堅(jiān)實(shí)的數(shù)據(jù)基礎(chǔ).
本文僅做學(xué)術(shù)分享,如有侵權(quán),請聯(lián)系刪文。


