<strong id="pcf7m"><optgroup id="pcf7m"><noframes id="pcf7m">
<dd id="pcf7m"></dd>
<dd id="pcf7m"><big id="pcf7m"></big></dd>

<button id="pcf7m"><acronym id="pcf7m"></acronym></button>

<dd id="pcf7m"></dd>

  • <em id="pcf7m"></em>
    <li id="pcf7m"><acronym id="pcf7m"></acronym></li><button id="pcf7m"><acronym id="pcf7m"></acronym></button>
    <span id="pcf7m"></span>

    <rp id="pcf7m"></rp>
  • <strong id="pcf7m"></strong>
    <rp id="pcf7m"></rp>
    <rp id="pcf7m"><object id="pcf7m"><input id="pcf7m"></input></object></rp>
  • 開源軟件供應鏈的研究框架、現狀和趨勢

    開源軟件已經成為現代社會的一項關鍵基礎設施, 支撐著幾乎所有領域的軟件開發. 通過安裝依賴、API 調用、項目 fork、文件拷貝和代碼克隆等形式的代碼復用, 開源軟件之間形成了錯綜復雜的供應 (依賴) 關系網絡, 被稱為開源軟件供應鏈. 一方面, 開源軟件供應鏈為軟件開發提供了便利, 已然成為軟件行業的基石. 另一方面, 上游軟件的風險可以沿著開源軟件供應鏈波及眾多的下游軟件, 使開源軟件供應鏈呈現牽一發而動全身的特點. 開源軟件供應鏈近年來逐漸成為學術界和工業界的關注焦點. 為了幫助增進研究人員對開源軟件供應鏈的認識, 從整體性的角度, 對開源軟件供應鏈給出定義和研究框架; 然后, 對國內外的研究工作進行系統文獻調研, 總結結構與演化、風險傳播與管理、依賴管理 3 個方面的研究現狀; 最后, 展望開源軟件供應鏈的研究挑戰和未來研究方向.

    原文引用:高愷, 何昊, 謝冰, 周明輝. 開源軟件供應鏈研究綜述. 軟件學報. http://www.jos.org.cn/1000-9825/6975.htm
    作者單位:北京大學軟件與微電子學院,北京大學計算機學院

    20 世紀末以來, 開源軟件取得了令人矚目的成就. 一方面, 隨著以 GitHub 為代表的代碼托管平臺的流行, 開發者普遍在這些平臺上進行軟件開發, 互聯網上積累了海量的代碼[1]. 截至 2021 年 10 月 1 日, GitHub 上托管了超過 2.5 億個代碼倉庫; 截至 2022 年 9 月 26 日, 編程問答社區 Stack Overflow (SO) 上發布了約 2300 萬個問題和 3400萬個回答. 另一方面, 開源軟件幾乎涵蓋軟件開發的所有環節, 并在市場占有率上逐漸媲美甚至遠超同類商業軟件. 從 Linux 操作系統 Red Hat Enterprise Linux (RHEL) 和 Android, 到深度學習框架 TensorFlow 和 PyTorch, 人們日常使用的軟件中隨處可見開源軟件的影子. 2021 年 Synopsys 分析了 17 個行業的 2 400 個商業代碼庫, 發現 97% 的代碼庫中包含開源代碼. 由此可見, 開源軟件已經成為現代社會的一項重要基礎設施, 支撐著幾乎每一個領域的軟件開發.

    (開源) 軟件的開發建立在對已有軟件或代碼的復用的基礎上. 通過安裝依賴、API 調用、項目 fork、文件拷貝和代碼克隆等各種形式的代碼復用, 開源軟件之間形成了供應 (即依賴) 關系. 隨著技術的發展和應用的深入, 開源軟件之間的供應關系網絡也愈發復雜[2]. 在這樣的網絡中, 一個被其他開源軟件復用的開源軟件, 同時還會復用其他開源軟件——即一個開源軟件可能既是上游供應者又是下游消費者, 從而開源軟件之間的供應關系網絡呈現出層級的結構, 逐漸形成了類似工業生產中的供應鏈.

    開源軟件供應鏈的定義:是指開源軟件制品之間在各自開發、構建、發布和運維過程中,通過安裝依賴、API調用、項目fork、文件拷貝和代碼克隆等形式的代碼復用,而形成的供應關系網絡. 也就是說,一個開源軟件可能既是上游供應者又是下游消費者, 從而開源軟件之間的供應關系網絡呈現出層級的結構, 逐漸形成了類似工業生產中的供應鏈。隨著技術的發展和應用的深入, 開源軟件之間的供應關系網絡也愈發復雜。

    隨著復用開源軟件在現代軟件開發中越來越普遍, 開源軟件供應鏈已然成為現代軟件行業的基石. 然而, 開源軟件供應鏈在為軟件開發帶來便利的同時, 也帶來不容忽視的風險問題. 一方面, 供應鏈上任何一個軟件的問題都可以沿著供應鏈影響大量的其他軟件, 使得影響被放大; 另一方面, 供應鏈上每一個軟件都會受到它直接或間接復用的軟件的影響, 使得問題的定位與解決變得困難. 近年來發生的一系列安全事件也印證了開源軟件供應鏈上的這些風險問題. 例如, 2016 年 3 月, 被整個前端開源生態依賴的 npm 包 leftpad 被開發者刪除, 對海量前端項目的構建和部署造成嚴重影響, 乃至影響了大量網站的正常運行; 2021 年 12 月, Log4j2 被曝光遠程代碼執行漏洞, 作為 Java 軟件項目的主流日志庫之一, 其對政府和企業的信息安全造成的影響難以計量.

    雖然軟件供應鏈被許多研究工作提及, 直到近年來, 才有學者嘗試對軟件供應鏈提出定義和研究框架. 例如, Zhou 等人[2]在 2019 年提出開源供應鏈定義為“由于軟件或軟件項目之間互相依賴 (如軟件的構建或運行時依賴, 開發者同時參與多個開源項目, 軟件代碼的復制粘貼等) 形成的復雜關系網絡”. He 等人[3]把軟件供應鏈定義為“一個通過一級或多級軟件設計、開發階段編寫軟件, 并通過軟件交付渠道將軟件從軟件供應商送往軟件用戶的系統”, 并進一步提出一個包含開發、交付、使用 3 個環節的軟件供應鏈安全研究框架. Ji 等人[4]定義開源軟件供應鏈為“開源軟件在開發和運行過程中, 涉及的所有開源軟件的上游社區、源碼包、二進制包、第三方組件分發市場、應用軟件分發市場, 以及開發者和維護者、社區、基金會等, 按照依賴、組合等形成的供應關系網絡”, 并進一步提出一個包含組件開發、應用軟件開發、應用軟件分發和應用軟件使用 4 個環節的開源軟件供應鏈安全研究框架. He 等人[3]和 Ji 等人[4]分別根據各自提出的研究框架, 綜述了軟件供應鏈上軟件制品生命周期內各個環節的安全風險及相關研究. 然而, 已有文獻綜述主要關注單個軟件制品的生命周期中的軟件供應鏈安全風險[3?7], 缺乏對軟件供應鏈的整體結構的審視和對鏈上軟件制品之間相互影響的相關分析. 因此, 為了深入理解開源軟件供應鏈的復雜性、動態性和軟件制品間的相互影響, 本文將從供應鏈整體視角, 對開源軟件供應鏈提出新的研究框架, 并基于該框架進行文獻綜述, 方便研究者針對開源軟件供應鏈開展進一步的研究工作.

    本文第 1 節首先對開源軟件供應鏈進行形式化定義, 并綜合考慮各種類型的軟件制品和各種形式的代碼復用, 舉出具體的開源軟件供應鏈實例. 第 2–5 節從這些定義和實例出發, 從結構及演化、風險傳播與管理和依賴管理 3 個方面對開源軟件供應鏈的研究工作展開綜述. 第 6 節總結了該領域的研究挑戰, 并對未來研究方向進行展望. 第 7 節對全文進行總結.

    1 開源軟件供應鏈定義

    在工業生產中, 供應鏈是一個很成熟的概念, 是指在創造產品并將其交付給消費者的過程中涉及的上游與下游企業所形成的網鏈結構. 而在軟件工程領域, “軟件供應鏈”這一概念出現較晚, 最早在 1995 年被 Holdsworth 提出[8], 用來描述通過制定具體的標準來設計和編寫軟件的整個過程. 此后, “軟件供應鏈”這一概念常被用來分析軟件工程中的經濟、管理和安全問題[9]. 本文參考現有工作[2?4]對軟件供應鏈的定義, 將開源軟件供應鏈定義為開源軟件制品之間在各自開發、構建、發布和運維過程中通過各種形式的代碼復用形成的供應關系網絡. 從這個定義出發, 可以將開源軟件供應鏈在數學上抽象為一個圖: G = <V, E>, 其中 V 表示軟件制品, E 表示軟件制品間的代碼復用關系. V 中的軟件制品類型可以相同, 也可以不同. 在軟件開發實踐中, 有 4 種典型的軟件制品類型 (如表 1 所示) 和 5 種典型的代碼復用關系類型 (如表 2 所示).

    軟件制品描述
    軟件包一些開發者會把自己編寫的軟件經過打包工具打包后上傳到包托管平臺供其他開發者下載使用. 大部分編程語言都有自己的包托管平臺, 比如Python的PyPI, Java的Maven和JavaScript的npm. 此外, 一些操作系統也提供了自己的包托管平臺. 在本綜述中, 軟件包、庫表達同一個意思
    代碼倉庫代碼倉庫包含一個軟件制品的開發歷史, 除了核心功能外, 代碼倉庫通常還包含測試、文檔等開發相關的文件
    二進制應用二進制應用是源代碼經過編譯等流程產生的二進制可執行文件, 比如Google Play上的安卓應用
    代碼片段開發者常將包含某些功能的開源代碼片段直接或經過修改后使用, 其中相當一部分來源于編程問答網站Stack Overflow的回答
    表 1 軟件制品類型
    代碼復用方式描述
    安裝依賴開發者會在軟件制品的依賴聲明文件里聲明依賴的軟件包和對應的版本, 供包管理器自動安裝相應的依賴
    API調用軟件制品在代碼中調用軟件包提供的API. 安裝依賴和API調用的區別是: 安裝依賴不一定會在代碼里使用. 比如, 有的安裝依賴是冗余的, 有的安裝依賴只能在命令行里使用
    fork完整克隆其他軟件制品 (尤其是代碼倉庫). 一個典型的例子是各大手機廠商對安卓操作系統的定制化
    文件拷貝復制粘貼其他軟件制品的代碼文件
    代碼克隆復制粘貼或修改其他軟件制品的代碼片段
    表 2 代碼復用關系類型

    2 文獻收集與分析

    為了對開源軟件供應鏈的研究框架建立整體性視角, 本文遵循系統文獻調研的流程[10]收集和分析相關文獻. 系統文獻調研的目標是找到盡可能多和盡可能全面的相關文獻. 常見的文獻搜索策略主要有數據庫檢索和“滾雪球”兩種. 我們這里采用“滾雪球”的方法進行相關文獻收集, 主要出于以下兩點原因.

    (1)正如第 1 節所示, 軟件供應鏈的含義相當廣泛, 難以形成既精確又全面的檢索詞.

    (2)軟件供應鏈是近幾年逐漸流行的概念, 一些早期的重要相關工作可能不會使用“軟件供應鏈”這一術語, 因此使用數據庫檢索可能會遺漏掉重要的相關文獻.

    “滾雪球”方法需要先確定一組起始的論文, 然后從這些起始論文出發, 通過前向搜索 (即收集論文引用的文獻) 和后向搜索 (即收集引用該論文的文獻) 的方式迭代找到新的相關文獻[11]. 我們選擇從近 3 年的 ICSE 和 FSE 會議論文中選出起始論文, 考慮到以下 3 點.

    (1)如前所述, 很難形成精確有效的搜索詞進行搜索.

    (2)ICSE 和 FSE 是軟件工程領域的兩個綜合性會議, 包容性高, 涵蓋的研究話題廣泛.

    (3)ICSE 和 FSE 是 CCF A 類會議, 論文代表性高, 受到學界的廣泛認可.

    通過閱讀近 3 年 ICSE 和 FSE 所有論文的標題、摘要和引言, 我們篩選出 13 篇研究開源軟件供應鏈的論文. 以這 13 篇論文為起始論文, 我們通過后向搜索和前向搜索迭代地進行論文收集和評估, 不斷找到新的相關論文. 在論文評估時, 一方面我們要找到研究開源軟件供應鏈的論文, 另一方面, 為了保證論文的質量, 我們只保留 CCF 推薦的國際學術會議和期刊的長文. 最終經過兩輪滾雪球后, 我們沒有找到新的相關文獻. 第 1 輪滾雪球我們發現 52 篇新的論文, 第 2 輪滾雪球我們發現 25 篇新的論文, 最后一共獲得 90 篇論文. 圖 1 展示了這 90 篇論文的發表年份分布. 可以看到, 最早進行開源軟件供應鏈的研究可以追溯到 2012 年, 并且開源軟件供應鏈吸引到了越來越多研究者的關注.

    開源軟件供應鏈的研究框架、現狀和趨勢
    圖 1 研究開源軟件供應鏈的論文的發表年份分布

    我們對這些收集到的論文進行閱讀, 建立了一個考察軟件供應鏈的整體性視角, 分析它們研究的軟件制品類型、代碼復用方式和具體研究方向, 分析結果展示在表 3 中. 考慮到開源軟件供應鏈是一個復雜、動態和相互影響的系統, 我們把相關研究分為 3 大方向: 開源軟件供應鏈的整體結構與演化, 上游軟件制品的風險傳播與管理, 和下游軟件制品的依賴管理, 分別有 30 篇、14 篇和 46 篇論文. 這 3 個研究方向的論文從整體到局部, 由泛入微地從不同的視角對開源軟件供應鏈展開了研究. 第 1 個研究方向關注的是對開源軟件供應鏈整體性質的刻畫, 后兩個研究方向關注的是供應鏈上軟件制品間的相互影響.

    開源軟件供應鏈的研究框架、現狀和趨勢
    表 3 相關文獻的數量分布, 按開源軟件供應鏈組成類型和研究方向劃分

    從供應鏈類型來看, 研究得最多的供應鏈類型是軟件包與軟件包之間通過安裝依賴形成的供應鏈 (下文稱為第 1 類供應鏈), 軟件包與代碼倉庫之間通過安裝依賴形成的供應鏈 (第 2 類供應鏈), 軟件包與代碼倉庫之間通過API 調用形成的供應鏈 (第 3 類供應鏈), 分別有 32 篇、23 篇和 14 篇論文. 對于第 1 類供應鏈, 研究者主要研究其整體結構與演化特征, 有 13 篇論文; 對于第 2 類和第 3 類供應鏈, 研究者主要研究其依賴管理, 分別有 19 篇論文和 7 篇論文. 這些研究內容的區別可能與使用的數據有關. 我們發現, 第 1 類供應鏈的研究以各大包托管平臺上軟件包的元數據為數據源, 這類元數據可以方便獲得, 其中通常包含軟件包的依賴信息, 使得研究供應鏈的整體結構與演化成為可能. 第 2 類和第 3 類供應鏈的研究則是選擇一些代碼倉庫, 分析這些代碼倉庫的依賴聲明文件或代碼中調用的 API 來構建供應鏈, 因為代碼倉庫的依賴聲明歷史和 API 調用行為可以很方便地獲得, 所以便于分析其依賴管理行為. 除了這 3 種類型的軟件供應鏈外, 其他類型的軟件供應鏈研究較少, 每種不超過 5 篇文獻. 這可能有兩方面的原因: 1) 一些供應鏈上存在的問題最近幾年才被意識到; 2) 大規模的代碼復用檢測如文件拷貝和代碼克隆較為困難, 需要的時間和空間資源太高.

    基于已有研究的軟件供應鏈組成類型、軟件供應鏈構建方法和具體研究方向, 我們進一步總結了如圖 2 所示的開源軟件供應鏈研究框架. 對于所有開源軟件供應鏈研究, 我們首先明確其研究的軟件供應鏈的類型, 即是什么軟件制品通過什么代碼復用方式形成的供應鏈; 其次, 明確數據源與供應鏈構建方法, 例如從 World of Code[12], GitHub, Stack Overflow 和/或各大包管理器平臺等數據源收集數據, 然后通過語言特定和代碼復用方式特定的方法工具解析收集的軟件制品的直接 (和間接) 依賴, 構造相應的供應鏈; 最后, 在結構與演化、風險傳播與管理和依賴管理 3 個方面中確定其具體的研究方向. 接下來, 我們將從結構與演化、風險傳播與管理和依賴管理 3 個方面, 對相關研究展開綜述.

    開源軟件供應鏈的研究框架、現狀和趨勢
    圖 2 開源軟件供應鏈研究框架

    3 結構與演化

    精準構建開源軟件供應鏈并探索其結構與演化是理解開源軟件供應鏈的第 1 步. 通過理解開源軟件供應鏈的結構與演化, 可以幫助我們認識開源軟件供應鏈的性質和特征, 支持有效發現潛在的問題, 支持核心軟件的孵化和培育. 形式化地看, 構建開源軟件供應鏈是通過收集一組節點 (即軟件制品) 并確定這些節點之間的邊 (即代碼復用) 來構造圖的過程. 因此, 構建開源軟件供應鏈需要首先明確節點是什么, 邊是什么. 鑒于代碼復用方式是構建開源軟件供應鏈的基礎, 接下來我們從代碼復用方式的角度對相關研究進行綜述.

    3.1 基于安裝依賴的開源軟件供應鏈

    安裝依賴是指軟件制品 (一般是軟件包和代碼倉庫) 在其依賴聲明文件里聲明的對其他軟件包及版本的依賴. 對于軟件包來說, 其安裝依賴一般在元數據里聲明, 可以通過其所在包托管平臺的 API 獲取. 此外, Libraries.io 收集了多個包托管平臺上所有軟件包的元數據, 方便研究人員開展軟件包之間安裝依賴的研究. 對于代碼倉庫來說, 其安裝依賴的獲取需要先把倉庫克隆到本地, 然后設計包管理器特定的腳本解析依賴聲明文件如 packages.json, POM.xml 和 requirements.txt. 因此, 從構建難度上看, 第 1 類供應鏈 (即軟件包與軟件包之間通過安裝依賴形成的供應鏈) 的構建較為容易, 也吸引了大量的研究.

    許多編程語言都有自己的包托管平臺, 上面托管了大量軟件包供開發者下載使用. 這些軟件包之間通過安裝依賴形成了 (第 1 類) 供應鏈. 隨著復用第三方軟件包在現代軟件開發中越來越普遍, 這些供應鏈對各編程語言的編程社區越來越重要. 研究者對多個包管理平臺上第 1 類供應鏈的結構與演化進行分析和比較. Wittern 等人[13], Kikas 等人[14]和 Decan 等人[15?17]分析了多個編程語言的包托管平臺 (包括 JavaScript 的 npm, Ruby 的 RubyGems, Rust 的 Crates, Python 的 PyPI, Perl 的 CPAN, R 的 CRAN, .NET 的 NuGet 和 PHP 的 Packagist) 上第 1 類供應鏈的結構與演化, 發現這些平臺上第 1 類供應鏈中軟件包、直接依賴和間接依賴關系的數量都在迅速增長; 其中只有一小部分軟件包被大多數軟件包依賴, 這一小部分軟件包的失效 (如被維護者刪除) 會影響到許多其他的軟件包, 降低供應鏈的彈性. 這些工作并沒有考慮到庫的每個版本的依賴和被依賴的情況, 于是 Soto-Valero 等人[18]對 Maven 平臺上庫的每個版本的依賴情況進行刻畫. 他們分析了 Maven Central 上 7 萬多個庫的近 150 萬個版本, 發現超過 30% 的庫有多個版本被其他庫的最新版本依賴, 尤其是對于流行的庫, 有超過 50% 的版本被其他庫的最新版本依賴. 他們還發現超過 17% 的庫有幾個版本的使用量遠高于其他版本. 與之前工作對第 1 類供應鏈上軟件制品的依賴分布進行刻畫不同, Zimmermann 等人[19]分析了第 1 類供應鏈的結構可能被用來發起供應鏈攻擊的機會. 他們對 npm 第 1 類供應鏈上軟件包之間的依賴, 軟件包的維護者賬戶和公開報告的安全問題進行了系統的分析, 發現單個軟件包可以影響到供應鏈的很大一部分, 其中極少數軟件包的維護者賬戶可以被用來向大多數的軟件包注入惡意代碼, 并且由于缺乏維護, 許多軟件包依賴有漏洞的軟件包.

    2016 年 3 月, left-pad 這個實現字符串左填充功能的只有 11 行代碼的 npm 軟件包被開發者刪除, 而它被另一個知名的 npm 包 Babel 使用, 導致它的刪除影響了包括 Facebook, Netflix 和 Airbnb 在內的大型網站的正常運行. left-pad 事件引起了研究者對小包 (trivial packages) 的關注, 并分析了這類包的普遍性、使用原因、發布原因和使用情況. Abdalkareem 等人[20,21]首先通過問卷調查的方式提出小包的定義為: 如果一個 npm 或 PyPI 軟件包的代碼行數不超過 35 行并且圈復雜度不超過 10, 那么這個軟件包就被認為是一個小包. 基于這個定義, 他們分析了 npm 和 PyPI 兩個平臺上小包的普遍性和開發者使用小包的原因. 他們發現 npm 和 PyPI 上小包是普遍存在的, 占16.0% 和 10.5%. 開發者使用小包是因為他們認為小包提供了良好的實現和經過測試的代碼, 但是作者發現 npm 和 PyPI 上只有 28% 和 49% 的小包有測試代碼, 且 18.4% 和 2.9% 的小包有超過 20 個安裝依賴. Chen 等人[22]調查了開發者發布小包的原因, 通過對 59 名發布小包的開發者的問卷調查, 他們發現 8 個開發者發布小包的原因, 包括創造可復用的組件、便于測試和記錄文檔、專注于具體的任務等, 以及 5 種小包帶來的問題, 包括發布者要維護多個軟件包、復雜的依賴、增加找到合適的軟件包的難度和增加重復的軟件包等. Chowdhury 等人[23]進一步分析了小包的使用情況. 他們發現在實際 JavaScript 項目中, 小包通常在核心代碼文件中使用, 且比非其他包被調用的次數要多. 在 npm 的第 1 類供應鏈上, 小包比其他包處于更加核心的位置, 移除某些小包可能影響供應鏈上29% 的軟件包. 綜上, 小包在軟件供應鏈上扮演著重要的角色, 但是其質量卻參差不齊, 開發者在使用小包時應該慎重選擇.

    除了對基于安裝依賴的供應鏈的依賴結構進行刻畫外, 研究者還分析了這類供應鏈的結構對鏈上軟件包的影響. 比如 Valiev 等人[24]分析了軟件包在第 1 類供應鏈上的位置對它的可持續性的影響. 他們使用 Katz 中心度來度量軟件包在供應鏈上的位置, 通過擬合 Cox 回歸模型, 發現 Katz 中心度與軟件包不活躍的機率有顯著正相關關系. Dey 等人[25]利用軟件包供應鏈的信息來預測 npm 軟件包的流行度的變化, 發現一個軟件包的上游或下游的數量變少或下載量的增加會提高它的下載量增加的機率. 他們進一步分析了 npm 軟件包供應鏈上開發者的貢獻行為[26], 發現開發者主要向他們直接依賴的軟件包提 issue 和 PR, 而向間接依賴的軟件包提 issue 和 PR 較少.

    3.2 基于 API 調用的開源軟件供應鏈

    除了在依賴聲明文件里聲明安裝依賴外, 軟件制品還可以通過調用軟件包的 API 來復用軟件包提供的功能. API 調用與安裝依賴的區別在于, 軟件制品的代碼中不一定會調用安裝依賴的 API, 因為安裝依賴可能是冗余的, 或者只能在命令行中使用. 從這個角度看, 分析 API 調用可以獲得比分析安裝依賴得到更精細的代碼復用關系. 然而相比分析安裝依賴, 分析軟件制品間的 API 調用更加復雜. 一方面, 需要對下游軟件制品的代碼進行分析, 另一方面, 還需要構建上游軟件包提供的 API 的數據庫. 研究者嘗試對兩種靜態語言 Java 和 Rust 語言的軟件包構建基于 API 調用的供應鏈. Hejderup 等人[27]實現了一個原型 PR?ZI 構建了 Rust 的包托管平臺 Crates 上軟件包之間基于 API 調用的供應鏈, 并與基于安裝依賴的供應鏈進行比較, 發現平均每個軟件包只調用 78.8% 的直接依賴的API 和 40% 的間接依賴的 API. Harrand 等人[28]則分析了 Java 的 Maven 平臺上庫之間的 API 調用關系. 他們從Maven Central 上收集了 94 個流行庫和 (安裝) 依賴這些庫的 829 410 個下游軟件包. 通過分析下游軟件包的字節碼, 他們發現 41.3% 的安裝依賴的 API 并沒有出現在字節碼中, 而對于所有的庫來說, 只有一小部分 API 會被其絕大多數的下游使用. 這些結果表明盡管都是對軟件包的代碼復用, 基于 API 調用的供應鏈與基于安裝依賴的供應鏈有很大區別, 后者會在分析漏洞等供應鏈風險傳播時產生過高估計.

    為了幫助研究者進行 API 調用層次的供應鏈研究, Ma 等人[12]構建了 World of Code. World of Code 收集了全網 1.7 億多個公開的 Git 代碼倉庫, 并對這些倉庫中使用主流編程語言編寫的代碼文件里的依賴導入語句 (如 Python 代碼中的 import 語句) 進行解析, 構建了代碼文件與調用的軟件包的映射. 基于 World of Code, 研究者針對通過API 調用產生的軟件供應鏈展開研究, 比如 Ma 等人[29]分析了這種類型的供應鏈對軟件包采用的影響, Tan 等人[30] 研究了 Python 深度學習供應鏈. Tan 等人通過 World of Code 提供的代碼文件與調用的軟件包的映射和 Libraries.io 記錄的軟件包的倉庫地址, 找到直接和間接依賴 TensorFlow 和 PyTorch 的軟件包和代碼倉庫, 構建了 TensorFlow 和 PyTorch 供應鏈. 他們分析了這兩條供應鏈的結構、應用領域和流行因素, 發現雖然這兩條供應鏈包含數十萬個倉庫, 但是都只有 5、6 層, 且約 90% 的項目在第 2 層, 即直接依賴 TensorFlow 或 PyTorch.

    3.3 基于文件拷貝的開源軟件供應鏈

    在軟件開發中, 從其他代碼倉庫或軟件包中拷貝完整的代碼文件到自己的項目中也是很普遍的. 基于文件拷貝形式的代碼復用的檢測可以通過比較文件的哈希實現. 一些研究者對代碼倉庫和軟件包之間文件拷貝的普遍性和維護情況進行分析. Lopes 等人[31]分析了 GitHub 代碼倉庫中文件拷貝的普遍性. 他們分析了 450 萬個非 fork 倉庫中的 4.28 億個 Java, C++, Python 和 JavaScript 代碼文件, 發現其中只有 8 500 萬個唯一的文件. 不同語言的文件拷貝情況有很大區別, 其中 JavaScript 代碼文件的重復率最高, 只有 6% 的文件是獨一無二的, 而 Java 代碼文件的重復率最低, 有 60% 的文件是獨一無二的. Hata 等人[32]分析了相同的文件在不同的項目里是如何被維護的. 他們分析了 32 007 個 GitHub 倉庫中的約 2 800 萬個重復的代碼文件, 發現這些重復的文件一般是庫、驅動文件和配置文件等, 但只有不到 40% 的文件會被所在的項目維護. 不同于這兩篇工作分析單個文件在倉庫間的重復情況, Wyss 等人[33]研究了 npm 軟件包之間的重復情況, 即一個軟件包完全復制或近乎完全復制另一個軟件包的代碼. 他們提出一個工具 Unwrapper 來檢測 npm 上軟件包的重復情況. Unwrapper 基于目錄樹的相似度和文件內容的相似度來度量兩個包之間的差異, 可以在 72.85 s 內快速比較一個軟件包和 npm 已有的所有軟件包. 利用 Unwrapper, 他們估計 npm 上約有 10.4% 的軟件包是重復的.

    除了代碼文件與調用的軟件包的映射, World of Code 還提供了代碼文件到代碼倉庫的映射. 通過其提供的 API, 可以快速找到一個代碼文件存在于哪些項目中, 便于開展基于文件拷貝的開源軟件供應鏈的研究. 比如 Imam 等人[34,35]分析了黑客馬拉松項目中的代碼文件復用情況. 他們分析了 22 183 個黑客馬拉松項目, 通過 World of Code, 他們發現這些項目中 85.56% 的代碼文件和 78% 的代碼行數是在黑客馬拉松之前創建的, 其中 69.54% 的代碼文件和 38.2% 的代碼行數是由黑客馬拉松隊伍外的開發者創建的. 這表明黑客馬拉松項目會大量復用其他項目的代碼, 這可能與黑客馬拉松項目要在有限的時間里完成有關.

    3.4 基于代碼克隆的開源軟件供應鏈

    代碼克隆形式的代碼復用在軟件開發中也很普遍, 開發者會復用其他項目或者 Stack Overflow 上的代碼片段. 目前已經有很成熟的代碼克隆檢測工具, 如 CCFinder[36], DECKARD[37]和 SourcererCC[38]等. 已有研究利用這些工具研究了代碼克隆在軟件制品中的普遍性. 比如 Abdalkareem 等人[39]分析了安卓應用克隆 Stack Overflow 上代碼片段的情況. 他們分析了 22 個開源的安卓應用代碼倉庫, 發現這些倉庫中或多或少都使用 Stack Overflow 上代碼片段, 平均 1.06% 的代碼 (按代碼行數衡量) 克隆自 Stack Overflow. 開發者使用 Stack Overflow 上代碼片段的主要原因是實現新功能和增強已有功能. 然而, 作者也發現文件在使用 Stack Overflow 上代碼片段后出現 bug 的比例會更高, 所以開發者應該注意使用的 Stack Overflow 上代碼片段的質量和后期維護. Gharehyazie 等人[40,41]分析了GitHub 上代碼倉庫間的代碼克隆情況, 發現倉庫間代碼克隆占倉庫內所有代碼克隆的 10%–30%, 且相當一部分的倉庫間代碼克隆是把整個文件、文件夾甚至整個項目拷貝過來并進行微小的改動. 他們還發現倉庫間代碼克隆現狀像一個洋蔥模型: 大部分代碼克隆都是克隆自同一個倉庫, 然后是克隆自同一領域的倉庫, 很少是克隆自不同領域的倉庫.

    3.5 小 結

    相關工作對基于安裝依賴、API 調用、文件拷貝和代碼克隆等代碼復用方式形成的開源軟件供應鏈的結構與演化開展了不同程度的研究. 盡管不同類型的軟件供應鏈 (如基于 API 調用的供應鏈和基于安裝依賴的供應鏈) 的圖結構不盡相同, 但是這些圖都具有如下相同的特點: 每個節點普遍與多個節點相連, 體現了圖的復雜性; 小部分節點可達圖中大部分節點, 體現了圖的脆弱性. 得益于數據的容易獲得, 基于安裝依賴的開源軟件供應鏈的結構與演化被廣泛研究. 而基于其他代碼復用方式的供應鏈, 要么由于代碼復用檢測復雜, 要么由于大規模數據收集復雜, 目前的研究仍然較少, 且或者集中在某些編程語言如 Java, 或者是在小規模數據上進行. 所有研究建立在數據基礎之上, 構造面向開源軟件供應鏈的數據基礎設施是當下開展供應鏈相關研究的迫切需要. 基于這些數據基礎設施, 對不同編程語言、不同領域和不同類型的供應鏈的結構與演化進行橫向比較, 探究其共性和差異, 對供應鏈的管理與維護也很有意義.

    4 風險傳播與管理

    在開源軟件供應鏈中, 一個軟件制品可能同時扮演著上游和下游的角色, 這使得一個軟件制品的風險可以沿著供應鏈傳播產生連鎖反應, 影響大量的下游軟件制品. 為了避免或控制供應鏈中的風險影響, 許多工作探索風險在開源軟件供應鏈上的傳播和管理實踐. 從形式上看, 風險傳播是在構建的圖中, 識別節點的變動 (如 API 變更, 軟件缺陷等), 并找到該節點可達的所有節點 (即下游軟件制品) 中受該變動影響的節點. 相關研究主要對 API 變更和軟件缺陷兩種類型的風險展開研究.

    4.1 API 變 更

    軟件包會不斷地發布新版本 (亦即, 持續演化), 在新版本中往往會加入新的特性、軟件缺陷 (例如軟件故障和安全漏洞) 的修復, 以及代碼重構等. 在這個過程中, 軟件包的 API 會發生變更, 影響到下游使用這些 API 的項目. 已有研究主要從上游 API 變更的引入情況、API 變更的影響范圍和 API 變更的應對實踐 3 方面展開.

    4.1.1 API 變更的引入情況

    在軟件包演化過程中, 會引入各種各樣的 API 變更, 其中會影響下游代碼正常運行的 API 變更被稱為不兼容變更 (breaking change). 不兼容更改會使得已有代碼無法兼容新版本, 影響下游用戶的升級. 已有研究主要分析了不兼容變更的普遍性、是否遵守 Semantic Versioning 和引入的原因, 且主要是在 Java 語言的軟件制品中展開.

    關于不兼容變更的普遍性, 已有研究在不同規模的數據集上的分析結果都證實了不兼容變更在軟件包演化過程中是普遍存在的. 比如 Wu 等人[42]分析了 22 個 Apache 和 Eclipse 項目中類、接口和方法的變更情況, 發現移除類和方法在這些框架里經常發生; Xavier 等人[43]分析了 317 個 Java 庫中不兼容變更的數量, 發現 14.78% 的 API 變更為不兼容變更, 且項目引入不兼容變更的頻率隨時間推移而增加; Raemaekers 等人[44]分析了 Maven Central 上 22 205 個軟件庫的約 15 萬個版本, 發現約 1/3 的版本引入至少 1 個不兼容變更.

    為了使用戶了解一個版本是否包含不兼容變更, Preston-Werner 提出了 Semantic Versioning 規范 (https://semver. org/). Semantic Versioning 規定了版本號為 MAJOR.MINOR.PATCH 的格式, 并約定: 若新版本引入了不兼容變更, 則應該增加主版本號 (MAJOR); 若新版本沒有不兼容變更, 且引入了向下兼容的新功能, 則應該增加次版本號(MINOR); 若新版本僅引入了向下兼容的問題修正, 則應該增加修訂版本號 (PATCH). 然而已有研究發現相當一部分軟件包并不會遵守這一規范. 比如 Raemaekers 等人[44]使用 Clirr 工具來分析一個軟件包相鄰兩個版本的 jar 包中包含的不兼容變更. 他們分析了 Maven Central 上 22 205 個軟件庫的約 15 萬個版本是否遵守 Semantic Versioning 規范, 發現主版本和次版本中不兼容變更的數量幾乎沒有不同. 然而 Clirr 工具檢測不兼容變更的準確性不高[45], 比如無法識別異常和繼承相關的不兼容變更, Ochoa 等人[46]使用更先進的不兼容變更檢測工具 japicmp[45] 對 Raemaekers 等人[44]的工作進行了一項外部和差異化的復現研究. 他們發現盡管 83.4% 的版本是遵守 Semantic Versioning 規范的, 但是仍有 20.1% 的次版本和修訂版本包含不兼容變更. 他們還發現遵守 Semantic Versioning 規范的版本比例隨時間上升, 包含不兼容變更的次版本和修訂版本的比例從 2005 年的 67.7% 下降到 2018 年的16.0%. 盡管 japicmp 可以解決 Clirr 的一些不足, 但是它仍不能識別泛型相關的不兼容變更. 此外, japicmp 在識別修飾符相關的不兼容變更上仍有改進空間.

    在引入不兼容變更的原因方面, Brito 等人[47]總結了 Java 庫的開發者引入不兼容變更的 3 大原因: 支持新的特性、簡化 API 和改善可維護性, 并且開發者主要使用版本發布紀要 (release note) 和更改日志 (change log) 記錄重大更改. 研究還發現軟件生態系統的規范也會影響開發者引入不兼容變更的行為[48,49], 比如 Eclipse 社區非常重視長期穩定性, 因此 Eclipse 社區的開發者會盡量避免引入不兼容變更.

    4.1.2 API 變更的影響范圍

    已有研究主要分析了兩種類型的 API 變更對下游項目造成的影響: 不兼容變更和 API 棄用 (deprecation). 與不兼容變更會破壞已有代碼不同, API 棄用并不會破壞已有代碼, 它只是作為一種信號, 提醒開發者該 API 可能會在未來的某個版本被刪除. 因此, 為了避免未來升級時軟件會出現異常行為, 開發者應及時對棄用的 API 進行調整.

    關于不兼容變更的影響, 盡管軟件包引入不兼容變更很常見, 但是已有研究均發現不兼容變更涉及的 API 很少被下游項目使用, 因此受影響的下游項目較少. 如 Wu 等人[42]設計了工具 ACUA 以分析 Apache 和 Eclipse 生態中 22 個框架的不兼容變更對 213 個下游項目的影響, 發現下游項目中 35% 的類和接口會使用上游框架提供的API, 但是只有 11% 的使用會受到上游 API 變更的影響. 然而 ACUA 無法識別基于反射機制的 API 使用方式, 這種情況可能需要復雜的靜態分析或動態分析才能識別. Ochoa 等人[46]設計了工具 Maracas 分析了上游不兼容變更對近 30 萬個 Java 項目的影響, 發現大多數不兼容變更涉及的 API 并不會被下游項目使用, 只有 7.9% 的下游項目會受到上游不兼容變更的影響. 盡管 Maracas 可以以非常高的準確率和召回率識別不兼容變更對下游項目的影響, 但是它仍存在幾點不足, 比如不能識別通過方法覆寫的方式調用發生不兼容變更 API 的影響, 不能識別 strictfp 和 native 修飾符相關的不兼容變更的影響等.

    已有工作主要分析 API 棄用對 Smalltalk 和 Java 項目的影響. 對于 Smalltalk 語言, Robbes 等人[50]分析了Squeak 和 Pharo 兩個軟件生態中上游 API 的棄用對下游的影響. 他們識別出 577 個被棄用的方法和 185 個被棄用的類, 發現只有很少一部分 API 棄用 (14% 的方法棄用和 7% 的類棄用) 會對下游項目造成影響, 這可能由于大部分棄用的 API 只在上游項目內部使用. 對于 Java 語言, Sawant 等人[51,52]分析了 Java 項目是如何對 5 個流行的第三方庫的 API 棄用和 JDK 中的 API 棄用做出反應的. 他們發現不同第三方庫的下游項目受 API 棄用影響的比例變化很大, 比如 Spring 的下游項目受影響的比例幾乎為 0, 而 Easymock 和 Guava 的下游項目受影響的比例超過 20%.

    4.1.3 API 變更的應對實踐

    研究者主要研究了 Smalltalk 和 Java 下游項目是如何應對 API 棄用的. 研究結果發現兩種語言的下游項目大部分都不會對上游 API 的棄用作出反應, 而做出反應的項目處理棄用 API 的方式也不同. 這可能由于 API 棄用并不會影響項目的運行, 或者處理棄用的 API 需要的成本和復雜度較高[53]. 對于 Smalltalk 項目, Robbes 等人[50]發現只有約 1/5 使用棄用 API 的項目會對棄用的 API 做出調整, 然而開始做出調整的時間和調整完成的時間可能會非常長, Hora 等人[54]發現下游項目做出的反應可能不同, 比如使用不同的 API 替換變更的 API. 對于 Java 項目, Sawant 等人[53]發現下游項目應對上游 API 棄用的 5 種模式: 不處理、刪除棄用的 API、用另一個 API 替換棄用的 API、用內部實現的方案替換棄用的 API 和回滾到之前的 API 版本. 他們分析了 20 萬個 GitHub 上的 Java 項目, 發現約 88% 的項目選擇不處理這些棄用的 API, 只有 0.02% 的項目會用推薦的 API 替換棄用的 API.

    4.2 軟件缺陷

    上游軟件制品的缺陷 (如安全漏洞、軟件故障、惡意代碼等) 會沿著供應鏈傳播, 對大量下游項目造成影響. 如何評估并控制上游軟件缺陷在軟件供應鏈上的影響, 是保障軟件供應鏈安全的關鍵. 目前研究主要從缺陷的傳播和上下游對缺陷的應對實踐兩個方面展開.

    4.2.1 缺陷的傳播

    軟件缺陷可以通過不同形式的代碼復用被引入到下游項目. 目前關于缺陷傳播的研究大都是針對安裝依賴形式的代碼復用, 還有一些文獻研究了通過文件拷貝和 API 調用等代碼復用形式發生的缺陷傳播. 此外, 軟件供應鏈攻擊也是近年的研究熱點:

    ■ 基于安裝依賴的缺陷傳播分析. 研究發現, 通過直接或間接依賴, 一個有漏洞的軟件包很容易進入大量代碼倉庫或軟件包的依賴樹. 比如 Decan 等人[55]分析了 269 個 npm 軟件包中存在的 399 個安全漏洞對 npm 上第 1 類供應鏈的影響, 發現這些漏洞可以影響到 7 萬多個軟件包. 然而這篇工作并沒有考慮到 npm 特有的依賴解析規則, Liu 等人[56]在考慮 npm 的依賴解析規則后, 構建了更準確的 npm 上第 1 類供應鏈, 發現 20% 的軟件包直接或間接依賴存在有漏洞的軟件包. 除了對其他軟件包的影響, Zerouali 等人[57]還分析了有漏洞的軟件包對下游代碼倉庫的影響, 發現約有 2/3 的 JavaScript 和 Ruby 項目會間接依賴有漏洞的 npm 軟件包和 RubyGems 軟件包. 不同于這些工作分析具體的漏洞在供應鏈的傳播, Massacci 等人[58]借用金融中杠桿的概念提出了軟件工程中的技術杠桿, 即軟件項目的直接和間接依賴的庫的代碼行數和使用的編程語言標準庫的代碼行數與軟件項目本身的代碼行數的比值. Massacci 等人分析了 Maven 項目的技術杠桿與有漏洞風險的關系, 發現高杠桿率會導致代碼帶有漏洞的風險的概率增加 60%. 前面這些工作都只關注了同一個語言生態內的漏洞傳播, 但是漏洞可能會跨語言生態傳播, 比如 Python 和 Java 項目可能會依賴用 C 語言編寫的第三方軟件包. 因此, 如果 C 軟件包發現漏洞, 依賴它的Python 和 Java 項目也會受到漏洞的影響. Xu 等人[59]設計了工具 Insight 來檢測依賴有漏洞的 C 軟件包的 Python 和 Java 項目. 通過對 PyPI 和 Maven 生態的分析, 他們識別出 8 萬多個直接或間接依賴有漏洞的 C 軟件包的 Python 和 Java 項目.

    盡管軟件會依賴各種各樣的軟件包, 但是這些軟件包的作用是不同的, 有的只在構建的時候用到, 有的只在測試的時候用到, 有的只是運行時需要. 比如, 通過對 100 個 JavaScript 項目的分析, Latendresse 等人[60]發現只有不到 1% 的依賴是在生產環境中需要的. Pashchenko 等人[61]分析了 SAP 公司使用最多的 200 個 Java 軟件庫, 發現約 20% 受漏洞影響的軟件庫實際并沒有被部署到生產環境. 這些發現說明在分析漏洞傳播時, 考慮依賴的實際使用場景可以大大減少分析的工作量.

    ■ 基于 API 調用的缺陷傳播分析. (直接或間接) 依賴有缺陷的軟件包并不意味著會受到缺陷的影響, 比如受缺陷影響的上游 API 并沒有被下游項目調用, 即使下游項目調用了有缺陷的上游 API, 其調用方式并不會觸發缺陷. 因此, 基于 API 調用對缺陷傳播進行可達性分析和可觸發性分析可以幫助我們更清楚地了解到哪些下游項目會真正受到缺陷的影響. 可達性是指下游項目調用了有缺陷的上游 API, 可觸發性是指下游項目對有缺陷的上游API 的調用方式可能觸發缺陷. Ma 等人[62]提出一種方法來估計上游 API 的 bug 對下游項目的影響, 該方法通過分析下游項目對有 bug 的上游 API 的調用路徑, 并結合 bug 的觸發條件, 利用 SAT 求解器來判斷下游項目的模塊是否會觸發上游 bug. 他們采用這個方法分析了 31 個有 bug 的上游 API 在 22 個流行 Python 項目的 121 個版本中的影響. 這 121 個版本中有 25 490 個模塊調用了有 bug 的上游 API, 但是只有 1 132 (4.4%) 個模塊可能會觸發上游 bug. 此方法可以準確定位出有 bug 的上游 API 影響的下游模塊, 適用于上游發現 bug 時, 下游項目評估上游bug 的影響. 但是此方法需要人工從問題報告中分析 bug 觸發條件, 導致該方法有兩點局限: 此方法需要問題報告中有明確的 bug 觸發條件描述; 此方法依賴大量的人工分析, 容易出錯. 未來可以探索從問題報告中自動提取 bug 觸發條件以解決上述局限.

    ■ 基于文件拷貝的缺陷傳播分析. 如果下游軟件制品拷貝了上游軟件制品中有漏洞的代碼文件, 那么下游軟件制品就會受該漏洞的影響. 基于文件拷貝的缺陷傳播可以通過比較文件的哈希是否在項目的目錄樹中來識別. Reid 等人[63]基于 World of Code 設計了工具 VDiOS 來識別有漏洞的代碼文件在開源代碼倉庫中的普遍性和維護狀態. VDiOS 工具以一個包含漏洞的代碼文件作為輸入, 基于 World of Code 提供的 API 找到該文件在 World of Code 收集的所有代碼倉庫中的完整拷貝和后續修改, 然后根據上游修復漏洞后的代碼文件, 將找到的文件分為 3 個狀態: 未修復漏洞、已修復漏洞和未知狀態. 通過對 4 個已知漏洞 (包括 OpenSSL 的 Heartbleed 漏洞) 的案例研究, 他們發現即使是活躍和很流行的項目也存在大量未修復的漏洞. VDiOS 只能找到完整拷貝有漏洞的代碼文件的項目, 如果項目對有漏洞的代碼文件進行修改或者只拷貝部分代碼片段, VDiOS 就無法識別出來. 此外, 由于World of Code 每半年更新一次, VDiOS 檢測的結果會有延遲.

    ■ 軟件供應鏈攻擊分析. Java, Python, JavaScript 等語言都有中心化的軟件包托管平臺, 負責軟件包的分發. 攻擊者常在這些平臺上分發惡意軟件包實施軟件供應鏈攻擊, 損害用戶的安全, 比如盜取開發者的證書. 一些研究者通過實際的軟件供應鏈攻擊事件, 總結軟件供應鏈攻擊的特征, 并設計工具識別軟件供應鏈攻擊. Duan 等人[64]設計了一個框架, 從安全機制、涉眾和攻擊消解技術等方面比較分析了 PyPI, npm 和 RubyGems 這 3 個軟件包托管平臺, 總結了它們的攻擊向量. 基于這些發現, 他們綜合元數據分析、靜態分析、動態分析等技術設計了面向包托管平臺的惡意軟件包掃描工具 MalOSS, 并在分析的 3 個平臺上發現 339 個新的惡意軟件包. Vu 等人[65]設計了工具 LastPyMile 來檢測軟件包的代碼倉庫和分發之間的文件差異, 以減少惡意代碼掃描工具要掃描的文件數量. Gu 等人[66]分析了軟件包生命周期中涉及的官方軟件包托管平臺、軟件包鏡像站和軟件包用戶, 識別了 12 個潛在的攻擊向量, 比如跳轉劫持攻擊、針對鏡像站特有軟件包的覆蓋攻擊等. 在此基礎上, 他們設計了工具 Rscouter, 對軟件包的元數據和事件進行分析, 識別潛在的安全問題. Ladisa 等人[67]通過對科學文獻和灰色文獻進行分析, 總結了一個包含 107 個攻擊向量的通用開源軟件供應鏈攻擊分類樹, 以及應對這些攻擊的 33 個措施.

    4.2.2 缺陷的應對實踐

    關于缺陷的應對實踐, 研究者主要從缺陷的修復時間和缺陷的修復方式兩個方面展開.

    研究者分析了不同供應鏈上缺陷的修復時間, 發現上下游軟件制品修復漏洞往往需要數月甚至數年的時間, 這增加了漏洞被攻擊者利用的機會. 比如 Alfadel 等人[68]發現 Python 上游軟件包中的漏洞一般需要 3 年的時間才會被披露, 且一半的漏洞是在漏洞披露后才被修復的. Prana 等人[69]發現 Java、Python 和 Ruby 的下游項目中漏洞持續時間較長, 一般要 3 到 5 個月才會被修復. Zhang 等人[70]分析了安卓內核供應鏈上的補丁傳播時間. 安卓內核供應鏈的最上游是 Linux 內核, 然后安卓開源項目 (AOSP) 基于 Linux 內核增加許多針對移動設備的新特性, 形成了 AOSP 內核, 接著芯片供應商如高通基于 AOSP 內核增加額外的硬件特定的更改, 最后 OEM 供應商如三星和小米基于芯片提供商的內核進行個性化的定制. Zhang 等人發現安卓內核供應鏈上近一半的漏洞是在上游修復 200 天后甚至更長時間才在 OEM 設備上修復, 10%–30% 的漏洞是在上游修復一年后才在 OEM 設備上修復. 漏洞修復的延遲主要是由于目前打補丁的實踐和 OEM 供應商缺乏對安全相關的上游提交的了解. Hou 等人[71]對分析了來自 153 個供應商的 6 261 個安卓固件中的漏洞修復時間, 發現 24.2% 的固件需要至少一個月來修復漏洞, 平均每個固件修復漏洞的時間為 3.2 個月.

    研究者從更新依賴版本、上下游合作等角度分析了在軟件供應鏈中軟件缺陷是如何被修復的. Decan 等人[55] 發現 npm 上 44% 的下游軟件包可以通過聲明寬松的版本約束與上游軟件包同時修復安全漏洞, 超過 40% 受影響的下游軟件包則因為使用的依賴版本約束不能自動更新到上游軟件包修復安全漏洞的版本, 這種情況需要下游軟件包在上游軟件包發布修復漏洞的版本后盡快升級. 但是 Chinthanet 等人[72]發現下游軟件包并不一定會很快更新到上游修復漏洞的版本, 這可能與更新版本需要花費很多努力來消除版本間的不兼容有關. Ma 等人[73]分析了下游開發者是如何處理因上游 bug 引起的 bug 的. 她們發現下游開發者定位到上游 bug 是困難的, 而堆棧記錄信息、與上游開發者溝通和熟悉引起 bug 的上游項目是對定位上游 bug 最有幫助的 3 個因素. 下游開發者在定位到上游 bug 后, 會采用不同的處理方法, 比如本地提出一個臨時的解決方案、限制上游項目的版本和等待上游項目修復等. Lin 等人[74]發現 Debian 和 Fedora 兩個 Linux 發行版中, 13.3% 的上游軟件包 bug 是由發行版的開發者修復的.

    4.3 小 結

    相關工作對開源軟件供應鏈上 API 變更和軟件缺陷兩種類型風險的傳播與控制展開研究, 分析了其引入情況、影響范圍和應對實踐. 研究結果表明風險可以沿著供應鏈對大量下游軟件制品造成影響, 而由于不清楚這些風險或處理這些風險的成本和復雜度較高, 很多下游軟件制品并不會處理這些風險或者很晚才會處理. 形式上看, 圖(即軟件供應鏈) 中上游節點的變動可以影響到大量的下游節點, 這與軟件供應鏈的圖結構是一致的, 但是下游節點很少根據上游節點的變動而變動.

    總的來說, 開源軟件供應鏈上的風險可以分為良性風險和惡意風險. 良性風險是由上下游軟件制品的異步演化造成的, 即上游軟件制品 (通常是軟件包) 在演化過程中會引入 API 變更, 代碼缺陷等, 這些風險是不可避免的. 當良性風險出現時, 它會立即沿著軟件供應鏈傳播, 對下游軟件制品的運行和維護產生影響. 增強上下游之間的溝通和協作是降低良性風險的有效措施. 下游用戶對良性風險的應對實踐取決于風險種類、處理成本等因素. 惡意風險是攻擊者通過分發包含惡意代碼的軟件制品來危害開發者的系統和隱私安全. 惡意風險需要利用各種手段吸引開發者下載使用進行傳播, 因此惡意風險的傳播是可以阻斷的. 通過分析攻擊向量, 識別出惡意風險的傳播途徑, 進而設計安全機制可以從源頭阻斷惡意風險的傳播.

    然而我們也注意到目前研究仍存在兩方面的問題. 一方面, 相關研究主要關注某些編程語言. 比如關于 API 變更的研究主要關注 Java 語言, 而缺少對其他編程語言的分析. 這主要是因為其他編程語言的代碼分析工具的缺乏. 另一方面, 相關研究分析風險傳播的方式比較單一. 比如相關工作主要研究了漏洞通過安裝依賴的傳播, 缺乏對漏洞通過其他代碼復用方式傳播的分析, 可能會導致漏洞影響的誤報和漏報. 考慮不同代碼復用方式下漏洞的傳播, 將更精確地評估漏洞在供應鏈上的影響.

    5 依賴管理

    一個軟件制品可以通過安裝依賴、文件拷貝、代碼克隆等方式復用其他軟件制品, 這些軟件制品又可以進一步復用其他軟件制品, 進而導致一個軟件制品有大量直接或間接依賴, 并受其影響. 因此, 如何管理這些依賴是一個重要問題. 研究者主要從依賴沖突、依賴更新、依賴遷移 3 個方面展開研究. 此外, 依賴降級、許可證合規、變更移植等主題等也被相關研究涉獵到.

    5.1 依賴沖突

    相關工作主要從依賴沖突的類型和依賴沖突的檢測與修復兩個方面展開.

    相關文獻主要研究了以下 4 種類型的依賴沖突.

    ■ 同一依賴的不同版本約束的沖突. 通過直接依賴或間接依賴的方式, 下游項目可能存在對同一軟件包的多個版本約束, 如果沒有一個版本可以同時滿足這些版本約束, 沖突就會發生[75?79]. 根據依賴管理工具的不同, 該類型的沖突會有不同的表現形式, 比如對于 Java, JVM 會根據某種版本仲裁策略選擇其中一個版本, 然后遮蔽其他版本. 如果加載的版本中不包含軟件項目需要調用的類或方法, 則會引發軟件崩潰[76,77]; 對于 Python, 如果沒有一個可以同時滿足多個版本約束的版本, 軟件制品則會構建失敗[78].

    ■ 同一依賴的不同版本的兼容性沖突. 軟件包在演化過程中會不可避免地引入不兼容變更, 進而導致一個軟件包的不同版本之間存在兼容性沖突. 比如 Jia 等人[80]分析了軟件包相鄰版本之間移除一個 API 和增加一個 API 兩種類型的不兼容變更. Wang 等人[81]分析了 Java 庫相鄰兩個版本同一個 API 的語義沖突.

    ■ 不同依賴的資源沖突. 不同依賴在全局共享資源如配置文件、文件格式、命名空間上也可能產生沖突[75,82]. 比如, JavaScript 并不提供顯式的命名空間, 這意味著所有庫共享一個全局命名空間. 因此, 一個庫的值或函數可能很容易被其他庫覆蓋、修改、刪除, 進而導致下游應用出現意外行為. Patra 等人[82]通過分析真實的案例, 總結了4 種類型的 JavaScript 不同庫的資源沖突: 導入沖突、類型沖突、值沖突和行為沖突.

    ■ 不同依賴管理模式的沖突. Go 語言在演化過程中產生兩種依賴管理模式. 在 Golang 1.11 之前, Go 項目通過 GOPATH 模式引用其他庫. GOPATH 模式通過 go get 命令把指定 URL 的庫的最新版本下載安裝到本地. 為了克服 GOPATH 只能安裝最新版本的限制, Golang 1.11 引入了更加靈活的 Go Modules 模式, 允許一個庫使用不同的引入路徑來引用一個庫的不同版本. 兩種模式對引入路徑的解析不同, 進而產生沖突. Wang 等人[83]發現 3 種發生依賴沖突的場景: 使用 GOPATH 模式的項目依賴使用 Go Modules 模式的項目、使用 Go Modules 模式的項目依賴使用 GOPATH 模式的項目和使用 Go Modules 模式的項目依賴使用 Go Modules 模式的項目.

    關于依賴沖突的檢測與修復, 目前工作主要首先從依賴沖突報告中總結沖突的表現形式和開發者采取的修復策略, 然后基于沖突的表現形式和修復策略, 設計自動化的沖突檢測工具. 沖突檢測工具的設計主要有兩種思路, 一種是構建項目的依賴樹檢測沖突, 然后利用 SAT 求解器等工具找到滿足所有約束條件的依賴版本集合; 另一種是通過構造測試樣例觸發沖突. 下面, 本文針對不同類型的依賴沖突介紹相關工作.

    ■ 同一依賴的不同版本約束的沖突. 該類型的依賴沖突主要是通過構造依賴樹來檢測, 然后利用 SAT 求解器等工具進行修復. Abate 等人[84]提出一個工具 distcheck, 基于軟件包的依賴配置文件中聲明的依賴關系, 利用 SAT 求解器檢測軟件包是否可以被成功安裝. Wang 等人[78]實現了一個工具 Watchman 對 PyPI 上由于庫更新導致的依賴沖突進行持續監控, 該工具通過分析每個軟件包的直接和間接依賴圖, 檢測依賴沖突, 并提供診斷信息幫助開發者理解沖突的導致原因, 促進沖突的修復. Li 等人[79]設計了工具 NuFix, 在.NET 項目的依賴圖上利用二進制整數線性優化模型找到符合開發者配置偏好的軟件包與平臺版本. Huang 等人[77]設計了工具 LibHarmo 來修復 Java 項目子模塊間依賴版本不一致的問題, 該工具首先分析 POM.xml 文件識別版本不一致的庫, 然后通過庫的 API 調用情況以及與開發者的交互, 推薦修復成本最小 (比如要刪除和改變的 API 調用數量最少) 的版本. LibHarmo 同樣局限于靜態分析的缺點, 不能處理如反射等形式的 API 調用, 會影響修復成本的估計.

    ■ 同一依賴的不同版本的兼容性沖突. Jia 等人[80]設計了工具 DepOwl 來檢測同一 C/C++軟件包不同版本因為 API 移除或 API 增加導致的兼容性沖突. DepOwl 首先檢測一個軟件包相鄰版本間移除和增加的 API, 然后檢測這些 API 是否在下游項目中使用, 進而確定下游項目可以使用的軟件包版本. DepOwl 依賴帶調試符號 (debug symbols) 的二進制文件來收集軟件包版本間的不兼容變更和下游項目中的兼容性沖突, 然而大部分軟件包和下游項目的二進制往往不帶調試符號. 為了解決這個局限, DepOwl 采用默認編譯指令將源代碼編譯成帶調試符號的二進制, 但由于實際編譯指令可能與默認編譯指令不同, DepOwl 會產生誤報. Wang 等人[81]提出基于構造測試用例的工具 Sensor 來觸發 Java 庫不同版本間的具有相同簽名的 API 語義不一致沖突.

    ■ 不同依賴的資源沖突. Patra 等人[82]提出了工具 ConflictJS 來自動檢測 JavaScript 庫之間在全局命名空間上的沖突. ConflictJS 包括兩步, 第 1 步動態分析每個庫在全局命名空間寫的位置識別潛在的存在沖突的庫; 第 2 步合成客戶端并比較它在不同潛在沖突的庫的配置下的行為, 如果行為不同, 那這兩個庫是沖突的.

    ■ 不同依賴管理模式的沖突. Wang 等人[83]分析了 Go 項目兩種依賴管理模式發生依賴沖突的原因: GOPATH 和 Go Modules 解釋導入路徑的方式不同和 Golang 生態并不嚴格要求執行語義版本發布規則, 以及 8 種修復策略, 如使用 Go Modules 的項目嚴格遵守語義版本發布規則、更新改變倉庫位置的庫的導入路徑等. 基于上述發現的原因和修復策略, 她們設計了基于項目依賴樹的工具 Hero 來自動檢測依賴沖突并建議修復策略.

    此外, 還有一些工具對多種類型的依賴沖突進行評估. 比如 Wang 等人[76]設計了一個靜態分析工具 Decca 來幫助開發者診斷軟件項目中依賴沖突問題的嚴重等級和維護成本; 他們還設計了工具 Riddle[85], 結合條件變異、搜索策略和條件恢復等技術自動生成測試用例來觸發依賴沖突引發的軟件崩潰, 收集軟件崩潰的堆棧記錄信息, 幫助開發者了解沖突.

    總的來說, 依賴沖突檢測是一個檢測供應鏈上某節點 (即下游軟件制品) 與其所有祖先節點 (即上游軟件制品) 構成的子圖中邊的屬性要求 (如版本約束、API 調用) 能否同時滿足的過程. 修復依賴沖突的思路是調整邊的某些屬性, 以使子圖中所有邊的屬性要求自洽.

    5.2 依賴更新

    依賴更新可抽象為圖中邊的版本約束屬性與其連接的上游節點的最新版本保持一致的過程. 上游軟件制品在不斷演化, 增加新的特性, 修復 bug, 滿足行業標準或者改善性能等. 從這個角度看, 下游軟件制品應該及時更新到新的版本[86]. 但是上游軟件制品的更新往往會伴隨著不兼容變更, 導致下游軟件制品的更新有很高的成本, 很多下游軟件制品仍在使用舊的上游版本. 相關工作主要從下游軟件制品更新的行為、(不) 更新的原因和自動化更新工具的效果 3 個方面展開研究.

    相關工作主要對安卓和 Java 項目的依賴更新行為展開研究, 發現大部分項目不會更新它們使用的依賴, 即使更新, 也是在上游依賴新版本發布數月后進行. 對于安卓項目, 已有研究發現大部分開發者不會更新所有依賴的安卓 API[87]或第三方軟件庫[88], 發生更新的第三方庫主要是 GUI 相關的, 為了使應用與最新的設計趨勢同步[89]. 對于 Java 項目, 已有研究發現約 80% 的項目在使用過時的依賴[90?92], 當依賴的項目新版本包含大量 bug 修復時, 下游項目更傾向于更新依賴, 而當依賴的項目新版本有大量 API 變更時, 由于升級需要進行相當多的代碼更改, 開發者不會輕易升級依賴[93,94]. 此外, 也有研究工作提出量度對基于安裝依賴的供應鏈上依賴的過時程度進行度量[95?99]. Zerouali 等人[96]提出的兩種度量供應鏈依賴過時程度的量度被廣泛使用.

    ■ 滯后時間: 一個軟件包的依賴的版本約束允許的最新版本與包托管平臺上該依賴的最新版本的發布時間之差.

    ■ 滯后版本: 一個軟件包的依賴的版本約束允許的最新版本與包托管平臺上該依賴的最新版本的版本號之差.

    已有研究[88,89]通過對開發者進行問卷調查的方式, 發現開發者不更新依賴主要有 4 個原因: 項目使用舊的依賴版本也能正常運行、害怕出現不兼容、不了解依賴的第三方庫發生更新和更新的成本過高. 比如 Derr 等人[88] 分析了 89 個安卓第三方庫的 1 971 個版本, 發現 58% 的版本變化不符合 Semantic Versioning 規范, 因此應用開發者無法正確評估升級庫的預期成本, 選擇繼續使用過時的版本. Huang 等人[91,92]同樣發現 35.3% 修復安全 bug 的庫版本中刪除了超過 300 個 API, 為庫的更新帶來很大的成本與風險.

    針對上述開發者不更新依賴的原因 (例如不了解依賴的第三方庫出現更新, 害怕出現不兼容), 一些自動化工具被提出來幫助解決上述問題. 比如 David-DM 會自動檢查一個項目的依賴是否過時, 如果過時了就會展示紅色的徽章提醒開發者. Greenkeeper 會自動檢查項目的依賴聲明文件中的依賴是否有更新, 如果有更新可用, 它會在項目內創建一個 branch, 在這個分支上進行更新, 并運行 CI 測試, 如果 CI 測試通過, 它會提交一個更新依賴的PR; 如果 CI 測試不通過, 它會在項目內提交一個 issue 報告, 通知開發者哪個依賴的更新沒有通過測試. 研究發現這些自動化工具的確可以提高開發者更新依賴的頻率[100], 但是其有效性仍然需要改進, 比如只有 1/3 的 Greenkeeper創建的 PR 會被合并[100], 很多 Greenkeeper 創建的 issue 占所有 issue 數量的一半, 且很多 issue 實際上并不是因為依賴更新造成的[101].

    5.3 依賴遷移 (庫遷移)

    形式化地看, 依賴遷移是圖中某下游節點移除與上游節點之間的邊并與其他類似節點建立新的邊的過程. 復用第三方庫在軟件開發中非常常見. 隨著下游軟件的演化, 其對上游第三方庫的需求可能會發生改變, 同時第三方庫在演化過程中也可能出現不被維護、出現安全漏洞等問題. 這時, 下游軟件的開發者會選擇遷移到另一個庫, 即移除對現在的第三方庫的依賴, 然后用另一個第三方庫替代, 這種現象被稱為依賴遷移, 在很多文獻中也被稱為庫遷移. 庫遷移在軟件維護中很常見, 但是這個過程通常是由開發者通過網絡搜索等方式收集多方面的信息然后分析和討論來決定的, 耗時耗力. 根據庫遷移的流程, 本文從遷移原因、遷移目標庫推薦、遷移 API 映射 3 方面對相關工作進行總結.

    研究人員主要通過挖掘版本開發歷史如 commit、issue 和 PR 來找到開發者公開討論的進行庫遷移的原因. Kabinna 等人[102]分析了 223 個 ASF 項目的 JIRA 中的 issue 報告, 總結了它們進行日志庫遷移的 5 個原因: 可以在一個項目里使用不同的日志庫、改善性能、減少代碼維護的成本、降低對其他庫的依賴和使用目標日志庫的新特性. He 等人[103]總結了開發者進行庫遷移 (不僅是庫遷移) 的 14 個原因, 其中被棄用的庫不被維護、目標庫的 特性和可用性更好、為了與項目更好地集成和簡化依賴是開發者提及的最頻繁的原因.

    開發者在決定進行庫遷移后, 需要決定遷移到哪個庫. 一些工作構建自動化工具為開發者推薦遷移的目標庫. 這些工具首先通過分析依賴配置文件[104,105]或 API 調用[106]的方式識別出項目依賴的第三方庫, 然后挖掘項目的歷史, 獲取項目的依賴變更歷史, 最后設計算法如關聯規則挖掘和排序[105]來識別遷移規則. 如 He 等人[105]從依賴 配置文件 POM.xml 中識別項目的依賴, 然后挖掘項目的依賴變更歷史, 識別出候選的遷移目標庫, 最后設計了 4 個量度對候選庫進行排序. 這些庫遷移推薦工具都依賴于實際發生的庫遷移, 因此都不可避免地受限于冷啟動問題.利用這些工具, 研究者還分析了庫遷移發生的領域和遷移趨勢, 發現庫遷移主要發生在日志、JSON、測試和網絡服務等幾個領域, 并呈現出非常高的單向性, 即一個庫要么被大多數項目棄用, 要么被大多數項目選擇[103].

    在確定遷移到的目標庫后, 還需要進行功能的替換, 即找到遷移庫和目標庫之間的 API 映射. 這些工具基于發生庫遷移的項目中相關的代碼修改片段識別遷移 API 映射. Teyton 等人[107]從同一個 commit 的同一個代碼修改片段中增加和刪除的 API, 構建遷移的庫和目標庫之間的 API 映射, 然后通過人工檢查的方式確定最終的映射關系. Alrubaye 等人[108]進一步提出一個自動化挖掘遷移 API 映射的方法. 給定一個被遷移的庫, 該方法首先挖掘項目的提交歷史, 識別出開發者修改調用它的 API 的 commit 集合, 然后提取所有包含移除方法和增加方法的代碼更改片段, 最后結合 API 的簽名和 API 文檔的相似性, 生成要遷移的庫和目標庫之間的 API 映射. Chen 等人[109] 提出一種無監督的深度學習方法. 該方法通過學習 API 使用和 API 描述 (API 名字和文檔) 的嵌入模型, 來推斷遷移庫與目標庫之間相似 API 的映射. 此方法只能產生一對一的 API 映射, 然而實際進行庫遷移的時候, 遷移庫和目標庫之間的 API 映射可能是多對一或一對多的, 甚至是多對多的.

    5.4 其 他

    除了從上述 3 個方面研究軟件供應鏈中下游軟件制品的依賴管理外, 研究者還從變更移植、依賴選擇、許可證合規和依賴降級等角度分析下游項目的依賴管理. Ray 等人[110]分析了 FreeBSD, NetBSD 和 OpenBSD 這 3 個項目間的變更移植行為, 發現這 3 個項目的每個版本中約 10%–15% 的代碼行數是移植自另外兩個項目的, 變更移植是定期發生的且主要由一小部分開發者完成. 同時移植的變更比非移植的變更出現缺陷的可能性更低, 這表明開發者更有可能選擇其他項目中經過良好測試的變更進行移植. Larios 等人[111]對來自 11 個不同行業的 16 名開發人員進行訪談, 并對 115 名參與選擇第三方庫的開發者進行調查, 來分析產業界開發者選擇第三方庫時考慮的因素. 基于訪談和調查結果, 他們總結了一套包含技術、人力和經濟 3 個方面的 26 個因素供開發者在選擇第三方庫時參考. Wu 等人[112]總結了開發者復用 SO 代碼的 3 大障礙: 需要太多的代碼修改才能在項目里運行、代碼 的實現不全面和代碼質量低. Baltes 等人[113]研究了開發者在使用 Stack Overflow (SO) 上代碼時是否遵守了 CC BY-SA系列許可證的要求, 即注明出處和許可證兼容, 他們估計 GitHub 上最多只有 1/4 的對 SO 上 Java 代碼片段的使用注明了出處, 且大多數注明 SO 代碼片段出處的方式并不符合 CC BY-SA 系列許可證的要求. Cogo 等人[114]發現開發者進行依賴降級要么是為了處理上游版本的問題如軟件缺陷、意外的特性變更或與其他依賴不兼容 , 要么是主動降級以避免上游依賴未來版本潛在的問題.

    5.5 小 結

    綜上所述, 相關工作主要從依賴沖突、依賴更新和依賴遷移 3 個方面對基于安裝依賴的軟件供應鏈中下游軟件制品的依賴管理問題進行研究. 這些工作揭示了下游軟件制品在管理依賴時面臨著問題多樣性、對上游缺乏了解和管理成本高等挑戰, 并且這些挑戰會隨著軟件包的增加和演化進一步加劇. 盡管已經有一些工具幫助開發者應對上述挑戰, 但目前仍存在兩方面的不足. 一方面, 目前的工具涵蓋的編程語言和問題類型較少, 比如同一依賴不同版本約束的沖突被廣泛研究, 而其他類型的依賴沖突研究則較少, 再比如 Java 語言的依賴管理 (尤其是依賴更新和依賴遷移) 問題被廣泛研究, 其他編程語言的依賴管理問題很少被研究; 另一方面, 工具的可用性還有待進一步提高, 比如 Greenkeeper 會產生大量依賴更新失敗的誤報, 給開發者帶來額外的負擔.

    6 開源軟件供應鏈研究的挑戰與展望

    開源軟件供應鏈已成為軟件行業的基石, 具有深刻的復雜性、動態性和低可見性. 現有文獻從結構與演化、風險傳播與管理, 以及依賴管理 3 個方面, 從整體到局部、由泛入微地對各種類型的開源軟件供應鏈展開了廣泛的研究. 本文分析與總結相關文獻, 提出下述挑戰.

    6.1 開源軟件供應鏈的構建及其數據基礎設施

    開源軟件供應鏈的構建是控制和管理開源軟件供應鏈的基礎. 厘清開源軟件供應鏈的結構, 一方面需要形成系統性的軟件供應鏈構建理論, 另一方面需要相關開源大數據基礎設施的支持.

    關于軟件供應鏈的構建, 本文將軟件供應鏈抽象為一個圖, 圖中的節點代表軟件制品, 邊代表代碼復用. 我們總結了 4 種典型的軟件制品類型, 包括軟件包、代碼倉庫、二進制應用和代碼片段, 以及 5 種典型的代碼復用方式, 包括安裝依賴、API 調用、fork、文件拷貝和代碼克隆. 這為軟件供應鏈的構建提供了模型基礎. 未來工作可以針對不同制品類型和代碼復用關系, 或者定位不同領域, 進行供應鏈構建, 并以此為基礎研究開源軟件供應鏈的基本性質和規律.

    關于開源大數據基礎設施, 目前比較流行的數據基礎設施有 Libraries.io、GitHub Dependency Graph、Open Source Insights 和 World of Code, 前 3 個基于安裝依賴構建, World of Code 提供了代碼文件的修改歷史與項目的交叉引用以及代碼文件與導入的軟件包的映射, 便于研究者構建基于文件拷貝和 API 調用的代碼復用形成的供應鏈. 未來工作需要對這些數據基礎設施中的數據內容進行交叉驗證, 保障數據的正確性和全面性, 同時構建數據基礎設施間數據實體的映射, 便于結合多個數據基礎設施開展供應鏈的研究; 另一方面, 需要保障數據基礎設施的及時性和高效更新, 提高其可用性. 此外, 面向二進制應用的供應鏈和面向代碼克隆的供應鏈的數據基礎設施仍是空白, 這需要大規模高效的二進制應用分析技術和代碼克隆檢測技術的支持.

    6.2 軟件供應鏈的風險評估與控制

    軟件供應鏈中上游軟件制品的風險 (如 API 變更和軟件缺陷) 可以沿著供應鏈廣泛傳播, 對軟件供應鏈造成巨大影響. 為了降低軟件供應鏈中的風險傳播的影響, 未來工作需要研究既系統又精細的風險評估與控制機制. 對于上游的 API 變更來說, 需要研究如何提高上游軟件制品對下游軟件制品復用情況的感知能力, 比如 API 調用頻率和調用方式等. 這可以幫助上游了解引入 API 變更對下游造成的影響, 做出對下游影響最小的 API 變更方式, 例如影響的下游項目數量較少、下游項目升級依賴版本時需要進行的修改最少、甚至可以通過自動化升級工具實現平穩升級等. 對于軟件缺陷來說, 需要研究: 如何保障鏈上高風險節點 (如被直接和間接依賴最多的軟件制品) 的安全, 從根源上避免漏洞的產生; 另一方面, 在漏洞發現后, 從可達性和可觸發性的角度精確找到受漏洞影響的下游軟件制品, 并及時把解決方案推送給下游. 最后, 優化軟件供應鏈的結構, 控制節點在供應鏈的影響范圍, 也是一種有效手段, 比如降低上游軟件制品的不可替代性等.

    6.3 面向開源軟件供應鏈的依賴管理

    通過各種形式的代碼復用以及直接和間接代碼復用, 一個軟件制品包含對大量其他軟件制品的依賴, 為依賴管理帶來了困難. 已有研究發現供應鏈上軟件制品的依賴管理面臨著問題多樣化、對上游了解不充分、管理成本高等挑戰, 并且這些挑戰還會隨著軟件制品的增加和演化而加劇. 因此, 需要研發更好的面向開源軟件供應鏈依賴管理的自動化工具來幫助開發者應對這些挑戰.

    針對問題多樣化的挑戰, 盡管相關工作已經提出一些工具自動化檢測和修復這些問題, 但是這些工具主要是針對 Java 項目, 對于其他編程語言的項目則研究較少. 考慮到不同編程語言遵循不同的設計模式和開發實踐, 不同語言的供應鏈上面臨的依賴管理問題和對應的解決方案也會有所差異. 有必要對其他編程語言的供應鏈上的依賴管理問題進行廣泛分析, 優化其依賴管理機制, 并尋找通用的解決方案.

    關于對上游了解不充分和管理成本高的挑戰, 首先需要結合相關數據基礎設施, 從不同代碼復用方式的角度檢測軟件制品中的上游成分, 然后設計自動化工具監控上游的演化, 評估上游演化對下游軟件制品的影響, 然后及時報告給下游開發者. 已有一些工具可能囿于項目本身數據質量的問題, 可能會產生大量誤報, 為開發者帶來額外的負擔. 因此, 提高工具的可用性也是需要解決的重要問題.

    7 相關工作

    隨著面向軟件供應鏈的研究越來越多, 一些研究者嘗試對相關文獻進行梳理、總結, 以促進進一步的軟件供應鏈研究. 這些綜述主要從軟件供應鏈安全的角度展開. 360 威脅情報中心的研究人員基于實際的軟件供應鏈安全事件, 從軟件生命周期的角度將軟件供應鏈抽象為一個包含開發、交付和使用等 3 個環節的模型, 被研究者廣泛使用. Zhou[5]基于典型的軟件供應鏈安全事件, 總結了 3 個環節的攻擊向量, 構建軟件供應鏈威脅模型. He 等人[3]總結了軟件供應鏈各環節風險防范技術的研究現狀, 然后從基本規范、風險評價和安全標準 3 個方面介紹了目前的供應鏈風險管理手段. Ji 等人[4]考慮到軟件中越來越多地使用開源組件, 在三環節模型的基礎上, 增加了組件開發環節, 并基于近 10 年的開源軟件供應鏈攻擊事件分析各環節的攻擊面, 然后從風險識別和加固防御兩個方面總結研究現狀. Wu 等人[6]介紹了靜態分析、動態分析、符號執行和污點分析等程序分析技術在軟件供應鏈攻擊檢測任務上的應用, 并分析了現有技術在軟件供應鏈攻擊檢測任務上的不足與挑戰. Ohm 等人[115]分析了 npm, PyPI 和 RubyGems 等 3 個軟件包托管平臺上 174 個被用來實施開源軟件供應鏈攻擊的惡意軟件包, 總結了這些惡意軟件包的攻擊方式和惡意行為.

    可以看出, 現有綜述主要關注軟件供應鏈的安全, 抽象出基于軟件生命周期的軟件供應鏈模型, 以此為基礎總結研究現狀. 然而, 這些綜述忽視了軟件供應鏈的整體結構和鏈上軟件制品之間的相互影響. 本文提出基于圖的開源軟件供應鏈模型, 從結構與演化、風險傳播與管理和依賴管理 3 個方面總結研究現狀, 提供一個了解軟件供應鏈復雜性、動態性和軟件制品間相互影響的整體視角, 彌補了現有軟件供應鏈綜述的不足.

    8 總 結

    開源軟件供應鏈在現代軟件開發, 乃至現代社會中, 扮演著越來越重要的角色. 開源軟件供應鏈牽一發而動全身的特點亟需我們從整體性視角去看待和分析. 本文把開源軟件供應鏈定義為各種軟件制品之間通過各種代碼復用方式形成的供應關系網絡, 并進一步總結 4 種典型的軟件制品和 5 種典型的代碼復用方式. 基于這些定義和實例, 本文對相關文獻進行收集和總結, 從結構與演化、風險傳播與管理和依賴管理 3 個方面總結相關文獻, 并展望了開源軟件供應鏈的研究挑戰與未來研究方向. 我們希望本文工作可以幫助人們增加對開源軟件供應鏈的認識, 促進未來的開源軟件供應鏈研究.

    參考文獻

    (略,請閱讀原文)

    【聲明】本文或部分內容轉載自 《軟件學報》,用于信息交流和學習參考之目的,不涉及商業用途。所涉及言論僅代表作者觀點,不代表本站立場。本文若存在權益侵犯或違規信息,請聯系我們處理。轉載請注明出處。
    網址引用: 開源軟件供應鏈的研究框架、現狀和趨勢. 思謀網. http://www.ahznzs.com/view/9404.
    (3)
    思謀科普組的頭像思謀科普組網站團隊
    上一篇2023年10月12日
    下一篇 2023年10月26日

    相關閱讀

    發表回復

    登錄后才能評論
    国产3p视频在线观看,国产又大又粗又硬又色,国产视频网站在线免费观看,亚洲AV无码VS国产AV