壽 增, 許睿超, 馬 驍, 狄躍斌, 柴赫求, 徐 劍
(1.國網(wǎng)遼寧省電力有限公司,遼寧 沈陽 110003;2.南瑞集團(tuán)有限公司(國網(wǎng)電力科學(xué)研究院有限公司), 江蘇 南京 210061;3.北京科東電力控制系統(tǒng)有限責(zé)任公司,北京 100192;4.東北大學(xué),遼寧 沈陽 110169)
目前,開源軟件已經(jīng)廣泛應(yīng)用到信息技術(shù)的各個領(lǐng)域。Gartner公司的調(diào)查報告顯示,99%的組織在其IT系統(tǒng)中使用了開源軟件,來自Sonatype公司的調(diào)查報告顯示,在參與調(diào)查的3 000家企業(yè)中,每年每家企業(yè)平均下載5 000個開源軟件。Github報告指出,超過360萬個開源項(xiàng)目依賴Top50的開源項(xiàng)目。同時,開源項(xiàng)目平均有180個第三方依賴組件,具體的依賴組件數(shù)量從幾個到上千個不等[1]。
然而,開源軟件帶來巨大便利的同時,也帶來了極大的安全挑戰(zhàn)。Snyk公司通過掃描數(shù)以百萬計的Github代碼庫和對超過500個開源項(xiàng)目的維護(hù)者進(jìn)行調(diào)查發(fā)現(xiàn):只有8%的開源項(xiàng)目維護(hù)者認(rèn)為自己擁有較高的信息安全技術(shù)水平,接近半數(shù)的開源項(xiàng)目維護(hù)者從不審計自己所寫的代碼,只有11%的維護(hù)者能做到每季度審核代碼。另據(jù)Linux基金會發(fā)布的《開源軟件供應(yīng)鏈安全報告》顯示,大量開發(fā)人員在開發(fā)軟件時并未遵守應(yīng)用程序安全最佳實(shí)踐。
開源軟件作為軟件生態(tài)中的重要組成部分,其安全性一直是工業(yè)界和學(xué)術(shù)界研究的重點(diǎn)和熱點(diǎn)。近年來,諸多開源軟件頻頻曝出高危漏洞,包括Jenkins、JBoss、Apache Tomcat、Docker、Kubernetes、Strusts2、OpenSSL、Jackson等。這些組件很多都應(yīng)用于信息系統(tǒng)的底層,并且應(yīng)用范圍非常廣泛,因此漏洞帶來的安全危害極其嚴(yán)重。國家互聯(lián)網(wǎng)應(yīng)急響應(yīng)中心的年度報告也顯示,開源項(xiàng)目依賴組件漏洞數(shù)量逐年增長,2019年組件漏洞數(shù)量較2018年環(huán)比增長72.99%[2]。面對日益嚴(yán)峻的開源軟件安全問題,越來越多的軟件研發(fā)人員意識到了開源軟件的安全與否極大地決定了整個信息系統(tǒng)是否安全。
軟件靜態(tài)分析是指在不執(zhí)行代碼的情況下,通過詞法分析、語法分析、控制流、數(shù)據(jù)流分析等技術(shù)對程序代碼進(jìn)行掃描,驗(yàn)證代碼是否滿足規(guī)范性、安全性、可靠性、可維護(hù)性等指標(biāo)的代碼分析技術(shù)。軟件靜態(tài)分析可以幫助軟件開發(fā)人員、質(zhì)量保證人員查找代碼中存在的設(shè)計性錯誤、代碼編寫錯誤、代碼編寫不規(guī)范以及安全漏洞等問題,從而保證軟件的質(zhì)量和安全。顯然,對開源軟件進(jìn)行靜態(tài)分析可以徹底而一致的檢查開源軟件的代碼,并可以及時地發(fā)現(xiàn)安全漏洞根源。因此,設(shè)計并實(shí)現(xiàn)一個高效的開源軟件靜態(tài)分析系統(tǒng)是非常必要和迫切的。
靜態(tài)分析和動態(tài)分析是代碼審計的重要方法。
靜態(tài)分析是在不運(yùn)行代碼的情況下,直接分析源代碼,常用的技術(shù)有基于正則表達(dá)式的關(guān)鍵字匹配、基于AST的模式匹配[3]、數(shù)據(jù)流分析[4]、抽象解釋[5]等。這些靜態(tài)分析技術(shù)各有優(yōu)缺點(diǎn),基于正則表達(dá)式的關(guān)鍵字匹配和基于AST的模式匹配局限于關(guān)鍵字和模式的限制,不僅維護(hù)成本大,而且漏報率和誤報率也很高;數(shù)據(jù)流分析是最常用的靜態(tài)分析技術(shù),文獻(xiàn)[5]是基于靜態(tài)分析技術(shù)的商業(yè)源代碼審計工具的典型產(chǎn)品,它的檢測效果優(yōu)于其他的基于靜態(tài)分析技術(shù)的產(chǎn)品,但是這類工具在面對大型開源項(xiàng)目時,其性能表現(xiàn)并不理想。
動態(tài)分析是在代碼運(yùn)行過程中發(fā)現(xiàn)漏洞,常見技術(shù)有污點(diǎn)追蹤[6]、符號執(zhí)行[7]等。符號執(zhí)行是動態(tài)分析的代表性技術(shù)。然而,在早期,由于計算能力的限制,符號執(zhí)行技術(shù)只被應(yīng)用于程序自動測試。近年來,隨著計算能力的提高,符號執(zhí)行技術(shù)得以取得長足的進(jìn)步,出現(xiàn)了動態(tài)符號執(zhí)行技術(shù)。動態(tài)符號執(zhí)行實(shí)際運(yùn)行被分析的程序, 在實(shí)際運(yùn)行的同時收集運(yùn)行路徑上的路徑條件, 然后翻轉(zhuǎn)路徑條件得到新的路徑條件,通過對新的路徑條件進(jìn)行求解得到新的程序輸入以再一次地運(yùn)行被分析程序, 從而探索與之前運(yùn)行不同的程序路徑[8]。動態(tài)分析技術(shù)對環(huán)境依賴高,不能保證源代碼的覆蓋率,且有可能產(chǎn)生路徑爆炸等問題。
隨著人工智能技術(shù)的發(fā)展,機(jī)器學(xué)習(xí)、深度學(xué)習(xí)被應(yīng)用于代碼審計中。文獻(xiàn)[9]應(yīng)用雙向LSTM模型,從易受攻擊的代碼段中學(xué)習(xí)模式,然而這類方法的主要缺點(diǎn)是需要花費(fèi)大量的精力來收集、清洗和標(biāo)記大量的訓(xùn)練樣本。文獻(xiàn)[10]提出了一種幫助安全分析人員進(jìn)行源代碼審計的方法。它可以通過檢查一小部分代碼來識別漏洞。文獻(xiàn)[11]指出不同的開發(fā)人員在實(shí)現(xiàn)相似的功能時,代碼具有相似性,因此,可以通過代碼不一致性檢測來發(fā)現(xiàn)軟件中的異常行為,進(jìn)而找出軟件中的漏洞。然而,文獻(xiàn)[11]中的方法往往只針對某一類具體的漏洞,不具備漏洞檢測的通用性。文獻(xiàn)[12-13]提出了檢測代碼中語法不一致的通用技術(shù)。這些工作依賴于抽象語法樹來查找不一致的代碼。然而抽象語法樹不具備語義感知功能,無法在更深層次上檢測代碼間的不一致性,因此能檢驗(yàn)出的漏洞種類有限。
基于代碼不一致性檢測思想,利用數(shù)據(jù)依賴圖,并結(jié)合圖神經(jīng)網(wǎng)絡(luò)聚類,本文設(shè)計了開源軟件的靜態(tài)分析系統(tǒng),該系統(tǒng)主要面向由C語言編寫的開源軟件。但是,其設(shè)計思想同樣適用于其他語言編寫的開源軟件系統(tǒng)。系統(tǒng)業(yè)務(wù)流程如圖1所示。
圖1 系統(tǒng)業(yè)務(wù)流程
系統(tǒng)的業(yè)務(wù)流程主要包括特征向量生成、功能聚類、不一致聚類以及不一致檢測。
(1)特征向量生成
首先,將目標(biāo)開源軟件使用LLVM編譯,得到字節(jié)碼;然后,使用過程內(nèi)數(shù)據(jù)流分析技術(shù)從每個函數(shù)中提取代表函數(shù)內(nèi)的基本操作或運(yùn)算的程序依賴圖。針對數(shù)據(jù)依賴圖進(jìn)行抽象,去掉控制依賴邊,僅保留數(shù)據(jù)依賴邊,得到數(shù)據(jù)依賴圖。
(2)功能聚類
針對生成的數(shù)據(jù)依賴圖,使用圖神經(jīng)網(wǎng)絡(luò)進(jìn)行聚類,得到具有相似結(jié)構(gòu)的圖,即代碼中功能相似的部分。
(3)不一致聚類
對具有相似結(jié)構(gòu)的圖進(jìn)行進(jìn)一步聚類,得到相似結(jié)構(gòu)中不一致的部分,即代碼中功能相似但實(shí)現(xiàn)不一致的部分。
(4)不一致檢測
并不是所有的不一致結(jié)果都是漏洞,因此,基于相關(guān)規(guī)則對聚類的結(jié)果進(jìn)行過濾,得到疑似的漏洞。
系統(tǒng)的檢測流程如圖2所示。
圖2 系統(tǒng)檢測流程
基于系統(tǒng)業(yè)務(wù)流程,系統(tǒng)所設(shè)計的功能包括:輸入處理、源代碼預(yù)處理、聚類與持久化、漏洞檢測與格式化輸出。其中輸入處理包括輸入檢測模塊;源代碼預(yù)處理包括預(yù)編譯模塊、程序依賴圖生成模塊、數(shù)據(jù)依賴圖生成模塊;聚類與持久化包括功能聚類模塊、不一致聚類模塊、持久化模塊;漏洞檢測與輸出部分包括漏洞檢測與輸出模塊。
1)輸入處理模塊:負(fù)責(zé)從用戶的輸入獲取參數(shù),并檢測是否合法,如果參數(shù)合法則調(diào)用系統(tǒng)其他模塊,實(shí)現(xiàn)對應(yīng)的功能。
2)預(yù)編譯模塊:主要負(fù)責(zé)將目標(biāo)開源代碼轉(zhuǎn)換成便于使用機(jī)器學(xué)習(xí)方法進(jìn)行分析的數(shù)據(jù)結(jié)構(gòu),該部分使用Clang將源代碼編譯成LLVM格式的中間代碼。
3)程序依賴圖生成模塊:使用文獻(xiàn)[14]中的工具將LLVM格式的中間代碼轉(zhuǎn)換成程序依賴圖。
4)數(shù)據(jù)依賴圖生成模塊:對程序依賴圖進(jìn)行抽象,將其轉(zhuǎn)換成數(shù)據(jù)依賴圖。
5)功能聚類模塊:將數(shù)據(jù)依賴圖轉(zhuǎn)換成特征向量,并通過聚類算法得到功能相似的數(shù)據(jù)依賴圖。
6)不一致聚類模塊:將功能相似的數(shù)據(jù)依賴圖通過聚類算法得到實(shí)現(xiàn)不一致的部分。
7)持久化模塊:將聚類的結(jié)果存入數(shù)據(jù)庫中。
8)漏洞檢測與輸出模塊:將系統(tǒng)聚類檢測的結(jié)果從數(shù)據(jù)庫中取出,進(jìn)行過濾,找到其中包含的漏洞,并且將疑似的漏洞格式化輸出。
(1)特征向量生成
用戶指定參數(shù),判斷參數(shù)是否合法,如果用戶輸入合法,進(jìn)行后續(xù)的系統(tǒng)功能調(diào)用,如果不合法,提示用戶需要輸入的參數(shù)并退出。通過用戶的輸入獲取目標(biāo)程序源代碼文件夾。調(diào)用Clang前端將目標(biāo)源碼從高層源碼轉(zhuǎn)換成底層的LLVM的中間代碼。示例程序以及其生成的LLVM中間代碼如圖3所示。
圖3 LLVM中間代碼
系統(tǒng)生成LLVM中間代碼之后,調(diào)用開源工具,將LLVM中間代碼轉(zhuǎn)換成程序依賴圖。程序依賴圖是一種包含大量的語義信息的程序表示方法,因此更適合以此為基礎(chǔ)再進(jìn)行特征向量的提取,進(jìn)行后續(xù)的功能相似性聚類。
如果僅僅使用程序依賴圖進(jìn)行后續(xù)的聚類,由于程序依賴圖包含的語義信息過多,聚類的效率會比較低。對程序依賴圖進(jìn)行簡化,可以得到抽象的數(shù)據(jù)依賴圖。示例程序的數(shù)據(jù)依賴圖如圖4所示。
圖4 數(shù)據(jù)依賴圖示例
(2)功能聚類
功能聚類模塊對抽象的數(shù)據(jù)依賴圖進(jìn)行聚類,得到相似的圖結(jié)構(gòu),即代碼中相似的功能,如圖5所示。
圖5 功能聚類
經(jīng)過功能聚類模塊的處理,可以得到結(jié)構(gòu)相似的數(shù)據(jù)依賴圖,為后續(xù)的不一致聚類做準(zhǔn)備
(3)不一致聚類
不一致聚類模塊進(jìn)行更精細(xì)的聚類,得到結(jié)構(gòu)相似的數(shù)據(jù)依賴圖中不一致的部分,如圖6所示。
圖6 不一致聚類
系統(tǒng)使用兩步聚類,得到功能相似但實(shí)現(xiàn)不一致的代碼的數(shù)據(jù)依賴圖,為后續(xù)的漏洞檢測準(zhǔn)備。
(4)不一致檢測
系統(tǒng)需要滿足用戶隨時查詢漏洞檢測結(jié)果的需求,所以持久化模塊是非常必要的,該模塊負(fù)責(zé)將聚類的結(jié)果存入數(shù)據(jù)庫中,方便用戶隨時獲取結(jié)果。該模塊將查詢的結(jié)果采用類似JSON的形式進(jìn)行存儲。
用戶需要獲取疑似的漏洞,并結(jié)合人工確認(rèn)漏洞是否存在,所以系統(tǒng)需要一個漏洞檢測與格式化輸出模塊負(fù)責(zé)篩選聚類的結(jié)果并將結(jié)果輸出。因?yàn)椴⒉皇撬械牟灰恢陆Y(jié)果都是漏洞,所以系統(tǒng)在得到兩步聚類的結(jié)果之后,還需要一些規(guī)則來將不一致的結(jié)果進(jìn)行過濾。該模塊基于三個規(guī)則:如果不一致集群中的所有結(jié)構(gòu)重疊,則忽略;如果一個不一致集群包含超過某一固定數(shù)量的偏離節(jié)點(diǎn),則降低優(yōu)先級;如果不一致聚類的數(shù)量超過某一個值,則降低優(yōu)先級。
系統(tǒng)測試環(huán)境如表1所示。
表1 測試環(huán)境
本文使用三個不同規(guī)模的數(shù)據(jù)集LibTiff[15]、libmp3lame[16]、bzip2[17]對系統(tǒng)進(jìn)行功能測試和性能測試。
在功能測試中統(tǒng)計了系統(tǒng)生成的DDG數(shù)量、聚類的結(jié)果數(shù)、疑似漏洞數(shù)以及經(jīng)過人工驗(yàn)證后確認(rèn)的漏洞數(shù),來驗(yàn)證系統(tǒng)的有效性。系統(tǒng)功能測試結(jié)果如表2所示。
表2 系統(tǒng)功能測試結(jié)果
在性能測試中,重點(diǎn)測試了代碼分析時間,如表3所示。
由表2和表3獲得的結(jié)果可知,系統(tǒng)可以在可接受的時間范圍內(nèi)給出了疑似的漏洞,并輔以少量人工分析,則可以得到較好的漏洞發(fā)挖掘結(jié)果。
表3 系統(tǒng)性能測試結(jié)果
在現(xiàn)有開源軟件靜態(tài)分析技術(shù)基礎(chǔ)上,設(shè)計了一個基于數(shù)據(jù)依賴圖聚類的開源軟件靜態(tài)分析系統(tǒng)。與其他基于機(jī)器學(xué)習(xí)的軟件靜態(tài)分析系統(tǒng)不同,本系統(tǒng)并不需要外部數(shù)據(jù)集,僅從開源軟件自身的代碼就可以進(jìn)行學(xué)習(xí),并檢測其代碼實(shí)現(xiàn)的不一致性;利用這些不一致性,并輔助少量的人工分析,就可以發(fā)現(xiàn)其中的安全漏洞。因此,該系統(tǒng)在開源軟件靜態(tài)分析方面具有一定的應(yīng)用價值。