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