陳克豪,程 偉,丁 蓀,劉 楊,3
(1.浙江理工大學信息學院,浙江杭州 310018;2.思探明信息科技有限公司,新加坡 128424;3.南洋理工大學計算機學院,新加坡 639798)
為節約成本、提高開發效率,大量開源組件被引入到在企業軟件開發過程中,且程序員不愿意使用新版本組件[1-2]。新加坡軟件安全公司Scantist 的調查報告顯示,97% 的軟件應用程序(包括企業軟件)依賴于某種形式的開放源碼[3],避免使用存在安全隱患的組件對于保證軟件安全具有重大意義[4-5]。當前安全測試步驟處于軟件開發過程中較為靠后的階段,且開發人員對軟件安全方面的技術不夠了解,安全測試人員對于軟件開發技術也不夠了解[6],存在信息不對等現象。軟件成分分析(Software Component Analysis,SCA)是指在開發過程中對應用程序進行分析,以檢測開源軟件組件是否存在已知的漏洞。例如,Imtiaz 等[7]對現有maven 和npm 源碼掃描的SCA 結果進行了橫向對比分析,著重對測試結果之間的覆蓋情況進行了比較,發現不同SCA 工具的檢測結果差異較大,并分析了這些差異可能產生的原因;Zhan 等[8]研究了安卓二進制文件SCA 識別的檢測效率、版本識別、混淆恢復能力等問題;Dann 等[9]對開源代碼的微小幅度修改對SCA 掃描準確性的影響進行了研究,并介紹了目前常見的開源組件修改方式及其對SCA 分析產生的影響;Dann 等[10]還對不同編譯器產生的不同字節碼文件對字節碼匹配產生的影響進行了研究,并設計了一種工具SootDiff,用于解決不同編譯器產生的字節碼文件不同而導致的匹配不準確問題。
近年來,隨著軟件開發周期縮短、迭代速度加快,安全測試越來越難以全面覆蓋[11],安全左移的概念隨之被提出,即將安全程序(代碼審查、分析、測試等)移至軟件開發生命周期的早期階段[12],從而防止缺陷產生并盡早找出漏洞,減少經濟損失[13]。為此,本文嘗試采用黑盒測試的方式研究安全左移的現狀,以及安全測試過程中采用SCA 方法應對各種安全左移場景下組件和漏洞分析結果的準確性,以了解安全左移對開源組件安全帶來的挑戰。
首先從現有學術文獻和主流搜索引擎中檢索以下關鍵詞及其相應的組合,分別為開源、組件、依賴、軟件成分、掃描、檢測及其對應的英文描述,以盡量覆蓋所有SCA 軟件;然后對檢索到的SCA 工具進行二次驗證,發現有些文獻中提及的SCA 工具無法在互聯網上找到相應鏈接,排除后得到21 個SCA 工具;最后基于以下條件進行篩選:①非老舊項目;②對于開源工具有編譯可執行文件,或可編譯出可執行文件;③對于商業工具能夠免費試用;④SCA 功能可正常使用。
通過篩選發現,大部分工具支持Java 語言,因此將不支持Java 的SCA 工具排除,最終篩選出Debricked、Github Dependabot、ScantistSCA、Synk、OWASP dependency check、Eclipse Steady 6 個SCA 工具。根據實際情況,在后續實驗中選擇合適的SCA 工具。由于每個SCA 工具產生的掃描報告標準與格式不統一,本文指定一套標準,將不同SCA工具檢測結果轉化為統一格式。
為使測試結果更完備,待測項目應盡可能包含各種不同情況。選取國內開源社區Gitee 的GVIP 項目,這些項目覆蓋了開發工具、服務器應用、運維、數據庫、插件、人工智能、區塊鏈等16 個不同領域的熱門開源項目。為使項目結構更加多樣化,挑選完全由Java 編寫的單模塊和包含多種語言的多模塊項目,其中有些多模塊項目明確定義了子模塊,有些以互相依賴的方式相關聯。下載這些項目對應的源碼并進行適當修改,使其能在本文實驗環境中通過編譯,最終篩選出13個工程共68個子項目。
現有文獻很少對安全左移場景進行系統性梳理,且由于大部分SCA 工具的具體實現原理是對用戶屏蔽的,很難直接評判這些工具是否支持相應的安全左移場景。為此,本文定義了一些規則和認定標準,梳理出以下安全左移場景:①開發過程中只使用經過審核的開源組件;②對上游廠商提供的組件進行安全檢測;③在項目正式開發前確定了依賴組件,希望能夠提前了解項目的安全性;④在開發過程中了解當前項目的安全情況。
對搜集到的SCA 工具進行左移場景支持情況統計,結果見表1。

Table 1 Support for secure left shift of the SCA tool表1 SCA工具安全左移支持情況
驗證性實驗的目的為證明安全左移會使SCA 產生偏移而導致測試結果不準確,從而誘發開源組件產生安全問題。本文實驗選取軟件開發過程中常見的安全場景之一,即在項目確定依賴組件時希望能夠提前了解其供應鏈安全性[14-15]。
OWASP TOP10 是軟件安全領域最知名的最危險安全漏洞類型榜單[16],2021 年該榜單的第一名為訪問權限控制破壞榜單。Apache Shiro 是一款強大且易用的Java 安全框架,近期其權限繞過漏洞頻發。基于此,選取幾個包含不同CVE(Common Vulnerabilities&Exposures)漏洞的Shiro 組件,在其基礎上進行二次開發得到新的組件,以構造間接引入的不安全項目。選取的Shiro 版本及對應的漏洞見表2。

Table 2 Shiro component version and corresponding CVE vulnerabilities表2 Shiro組件版本及對應的CVE漏洞
首先對構建的4 個項目進行漏洞利用,結果發現這4個漏洞都能夠被成功利用。將4 個項目的BOM 文件以pom.xml 的格式提取出來用于模擬安全場景,使用Snyk 進行基于BOM 和源碼SCA 的SCA 檢測[17]。對于基于BOM的SCA,共檢測出372 個漏洞,148 個組件依賴;對于基于編譯的SCA,共檢測出388 個漏洞,201 個組件依賴。漏洞數量比組件多的原因為許多漏洞被多個組件重復報告,這些組件之間有傳遞的依賴關系。此外,二者組件數有明顯差距,漏洞數差距不大,且對于特意間接引入的Shiro 組件漏洞,所有安全左移場景下的SCA 均無法檢測出。根據基于編譯的漏洞掃描結果對項目進行漏洞修復,然后再次對程序進行驗證,發現漏洞已經無法再次被利用。該結果證明編譯場景下SCA 工具對于軟件安全有非常重要的作用,安全左移將會導致測試結果不準確。
現有SCA 工具的測試側重點多為對于IDE、CI/CD 工具的支持情況,并沒有量化數據的準確性,而本文更多關注數據準確性方面,希望將關注點從各種繁雜的IDE 和DevOps[18]工具中剝離開來。各種安全左移場景中集成的SCA 工具實際上調用的是底層服務,檢測這些安全左移場景的準確度,最終將其轉化為檢測SCA 工具對于二進制文件、BOM 文件、源碼等的掃描準確度問題。
對于安全左移場景1,其準確度完全依賴于SCA 工具本身使用的漏洞數據庫,無法評估其檢測結果的正確性[14]。另外3 種安全左移場景下的代碼可以依據自身存在的蛻變關系將測試結果與傳統場景下的SCA 進行比較。因此,本文對這3 種安全左移場景進行研究,嘗試揭示現有SCA 工具在安全左移場景和傳統使用場景下的表現差異。除開源SCA 工具外,其他工具的內部實現原理是未知的,因此本文采用黑盒測試[19]的方式進行實驗。
基于二進制文件和源代碼編譯模式的SCA 之間存在一種蛻變關系,即二者依賴的組件和漏洞是相同的。為避免不同SCA 工具自身掃描結果存在誤差的情況,本文對同種SCA 工具的二進制掃描結果與編譯后的掃描結果進行比較,選擇的SCA 工具為ScantistSCA 和OWASP Dependency Check。
使用編譯將待測項目集打包為二進制文件。通常情況下,對于Java 項目,二進制文件有.jar 和.war 兩種格式,而.war 文件是不會作為組件依賴被引入項目之中的,即不存在一種安全左移場景會使用.war 文件,因此從實驗數據中去除會生成.war 文件的項目數據。多模塊項目在編譯過程中會產生多個.jar 文件,因此在統計多模塊項目數據時對于父模塊包含子模塊的項目,其父模塊的jar 包已經依賴了子模塊,則只對父模塊的jar 包進行測試;而對于不存在父子關系的多模塊項目,則對每個子模塊打包得到的.jar文件進行測試。
該實驗的目的為探究SCA 工具對BOM 文件的檢測支持情況,了解安全左移場景3 下的安全初步評估與項目開發完成后實際安全情況的誤差。對于maven 項目來說,其BOM 文件為pom.xml。由于目前可使用的SCA 工具并不能直接對pom.xml 文件進行處理,本實驗采用源碼SCA 的方式間接實現基于BOM 的SCA 檢測,即在原始項目數據的基礎上編寫腳本提取出的pom.xml文件,以此構建空的maven 項目,然后對該項目進行源碼掃描作為基于BOM 的SCA。由于源碼掃描分為編譯和不編譯兩種情況,使用不同方式對同時支持這兩種方式的SCA 工具進行測試,并在實驗統計階段將前端的js 等非Java 項目的數據從結果中去除。
本實驗使用的SCA 工具為Github dependabot、Eclipse Steady、ScantistSCA、Snyk、OWASP dependency check,實驗最后統計漏洞數、依賴數、不安全依賴數,并根據漏洞、依賴列表之間的差異得到BOM 文件檢測相對于源碼編譯檢測的精確度(precision)、召回率(recall)、F1 分數(F1-score)等結果,計算公式分別為:

式中,TP 為真正例,FP 為假正例。
不經過編譯的依賴樹結構是通過模擬方式生成的,與實際結果有一定偏差。在安全左移場景下,項目很有可能不被編譯通過。在SCA 工具的內部實現中,經常會對不能編譯的項目進行依賴樹的模擬生成,以此得到其間接依賴。本實驗的目的為探究各SCA 工具在不編譯情況下模擬生成的依賴相較于編譯得到的結果偏差,以此了解SCA工具在不能編譯項目的安全左移場景下的精確度情況。采用同時支持不編譯掃描和編譯掃描的SCA 工具對項目進行測試,比較源碼編譯結果的精確度、召回率、F1分數。
對最終生成jar 包的項目進行編譯,得到43 個不同的jar,對這些.jar 文件進行二進制掃描,對工程文件進行編譯的SCA 檢測,數據統計結果見表3,其中dep、dep*、vuln 分別表示組件數、不安全的組件數、漏洞數。
對上述數據進行去重,然后統計二進制與編譯方式的SCA 掃描結果分布情況,并繪制韋恩圖,見圖1。可以看出,二進制SCA 掃描與編譯SCA 掃描結果存在較大差異,尤其是漏洞數相較于組件數方面難以分辨。分析其原因可能為大多數Java 項目都采用Spring Boot 腳手架進行構建,Spring Boot 默認使用插件進行打包,在打包過程中會將jar 包構建為fatjar,給二進制掃描帶來了挑戰。同時二進制文件的編譯過程中存在代碼混淆的情況[20-21],如將標識符重命名為無意義的信息、給字符串信息進行加密、對未知文件進行移動、將代碼轉化為偽代碼字節流等,這些都會給二進制SCA 造成不便。對于Java 語言來說,使用不同的編譯工具也會使編譯結果的字節碼文件不相同,這可能是導致二進制SCA 與基于編譯模式的SCA 結果差異巨大的原因。
采用Scantist 和Snyk 對BOM 文件進行SCA 檢測時可通過基于源碼編譯和不編譯兩種方式得到數據。值得注意的是,Snyk 在采用編譯SCA 方式掃描時存在報錯而不能正常通過掃描的情況。命令行日志中提示的原因為不能生成依賴樹的命令,源自于maven 無法在中央倉庫中找到一個依賴的jar 包,而這個jar 包是子模塊的jar 包,在此之前mvn install 已經安裝到本地倉庫,且在本地maven 倉庫中能找到對應的jar 包,執行mvn dependenchy:tree 命令能夠正常生成依賴樹。使用其他SCA 工具并不存在這樣的問題,因此對于基于編譯的SCA 支持不佳的現象可能是由于Snyk 本身不夠完備,這也說明了源碼直接檢測雖然在準確度方面可能存在一定問題,但也帶來了檢測成功率高的優勢。

Fig.1 Wayne diagram of binary and compiled SCA result圖1 二進制與編譯SCA結果韋恩圖
基于BOM 的SCA 檢測相較于編譯SCA 的偏差情況見表4。可以看出,Snyk 的source control 和Scantist 的airgap模式相較于其他模式偏差較大,原因可能為這兩種模式是對源代碼進行分析后對依賴樹進行模擬生成,這與基于編譯的SCA 掃描的實現原理有較大差異,且其源代碼是不完全的,最終導致偏差較大。其他幾個針對pom 文件進行的SCA 掃描均基于編譯模式,因此數據比較接近。Github Dependabot 的精確度、召回率等指標全部為1,意味著其在安全左移場景下不會產生任何偏差,這個結果不在預期之中。通過查閱資料了解到其源碼SCA 檢測結果本身就是不準確的,Dependabot 僅對BOM 文件中的信息進行檢測[22],而源碼中的BOM 文件是相同的,因此導致最后檢測結果相同。

Table 3 Comparison of binary and source compiled SCA表3 二進制SCA與編譯SCA比較

Table 4 Deviation between BOM SCA and source compiled SCA表4 基于BOM的SCA檢測相較于編譯SCA的偏差
所有SCA 工具測試結果中漏洞檢測精確度和召回率均較高,這是由于一個漏洞可能會被多個不同組件引入或組件之間存在依賴關系,從不同地方發現了同一個漏洞,該種安全左移場景下的漏洞檢出率較高。所有基于編譯方式對pom 文件進行的SCA 掃描精確度均接近于1,而召回率存在一定差距,召回率較高的為Eclipse Steady 和Scantist的bom detect模式,這說明對pom.xml文件進行SCA掃描的安全左移場景誤報概率較小,主要是由于出現數據不完整而造成漏報。
不同SCA 工具對于是否處理編譯和不編譯模式存在差異。例如Scantist 的命令行工具提供了airgap 模式,在該種模式下,Scantist 將不會對源碼進行編譯處理,而是通過對源碼進行檢測模擬生成依賴樹來進行掃描。而Snyk 的命令行工具在執行測試命令前要求項目能夠使用mvn install 命令進行編譯,如果項目無法編譯通過,Snyk 的測試命令將因無法正常執行而拋出異常。在實測過程中發現,執行Snyk 命令行時實際上是調用maven 命令生成依賴樹,因此Snyk 使用命令行工具是以編譯的方式進行檢測的,對于那些Snyk 不能正常導入的項目則通過Git倉庫集成的方式得到掃描結果,而這種方式顯然是不編譯的。
基于源碼的不編譯與編譯模式SCA 結果比較見表5。可以看出,Scantist 和OWASP Dependency Check 兩個工具在組件數和有漏洞的組件數方面存在較大偏差,在漏洞數檢測方面均表現較好。分析原因可能為多個組件會引入同一個漏洞,最終同時被檢測出。導致組件數結果不準確的原因在于不編譯方法的依賴樹信息是基于代碼信息模擬生成的,組件及其依賴關系是通過推測得到的,由于模擬生成依賴樹的每一層都有偏差,最終導致其與編譯SCA方法生成的依賴樹相差較大。

Table 5 Comparison of results between uncompiled and compiled modes based on source code表5 基于源碼的不編譯和編譯模式結果比較
本文提出在安全左移場景下開源組件安全可能面臨的挑戰,并設計了多組實驗對不同安全左移場景下的開源組件安全檢測準確率進行研究。結果顯示,現有SCA 檢測工具在安全左移場景下的檢測結果均產生了較大偏差,進而對偏差產生的原因進行分析,為SCA 檢測的優化方向提供了參考。然而,本次實驗僅針對Java 語言和maven 構建工具展開,對于其他編程語言和構建工具不一定具有適用性。后續將針對基于其他編程語言和構建工具的軟件開發在安全左移場景下的開源組件安全進行研究,同時將通過融合SCA 構建出漏洞檢測和自修復的二進制制品倉庫,為安全左移場景下的軟件開發提供更多網絡安全保障。