開源軟件供應鏈安全系列:OSS風險點與預防
一. 開源軟件供應鏈安全的興起
Verocode研究結果表明[1],在開源組件倉庫中70.5%的代碼庫存在安全漏洞,而這些安全漏洞風險46.6%是由其他開源項目直接、間接引進所導致的。超過96%的產業機構在其開發實現的軟件應用代碼庫中使用開源組件。由于開源體系安全意識的淡薄以及代碼重用的盛行,這一比例將持續擴大。
開源軟件供應鏈是指開源軟件在開發和運行過程中,涉及到的所有開源軟件的上游社區、源碼包、二進制包、第三方組件分發市場、應用軟件分發市場,以及開發者和維護者、社區、基金會等,按照依賴、組合等形成的供應關系網絡。
軟件供應鏈安全包括兩部分,一是引入的開源組件包中存在漏洞,二是引入的開源組件包中存在攻擊者精心制作的惡意代碼。
開源組件與閉源組件有著天差地別的差異,由于大部分開源組件的作者知名度不大,開發流程不完善,使用者往往缺乏專業的代碼審計技能,缺乏知名公司信譽以及購買合同作背書,并且攻擊者能隨時下載代碼做審計發現漏洞,甚至參與到發布流程中,安全風險點大大增加。例如,2020年SolarWinds的 SUNBURST攻擊事件是由于閉源的原因,攻擊者需要攻擊到公司內部的資源才能實施投毒,攻擊代價更大,相反用戶對開源軟件的安全性沒有閉源軟件那么信任。
二. 開源軟件供應鏈中引入的漏洞
第三方組件依賴及代碼復用可能導致開源組件上游的漏洞被引入到下游的組件及應用軟件中,例如從GitHub抄寫代碼,從PyPI、Maven拉取開源組件包,都可能引入已經披露的漏洞。
針對第三方組件依賴,2014年首次披露的HeartBleed攻擊是加密程序組件OpenSSL暴露的一個漏洞,當年在最熱門的啟用TLS的網站中有80萬個網站含該組件依賴,且有1.5%易受心臟出血漏洞的攻擊[2]。
針對代碼復用,2018年在WinRaR中發現的漏洞(CVE-2018-20250)可導致受害者計算機完全被攻擊者控制,該漏洞存在于unacev2.dll模塊中,相關代碼被其他220余款軟件復用,包括BandZip、好壓等,上述軟件均受到該漏洞的影響。
Log4j是Java生態中非常流行的日志記錄第三方庫,Spring是Java Web開發中非常流行的Web開發框架。攻擊者利用Log4j與Spring中的遠程代碼執行漏洞(CVE-2021-44228),進而可以控制以及竊取宿主機器上的敏感信息。根據Google安全團隊的報告,Maven生態中超過8%的第三方庫都受到Log4j漏洞的影響。Maven生態用戶基數龐大,有很多知名框架(Struts2、Solr、Druid、Flink、ElasticSearch、Kafka等等)使用該組件,可見其覆蓋的影響面非常廣泛。
三. 開源軟件供應鏈安全攻擊風險點
開源軟件除了引入漏洞等不安全因素,在使用的過程中還包含人為攻擊的各種風險點。和其他安全風險相似的是,攻擊者的主要手段是數據泄露、獲取主機的權限、拒絕服務攻擊以及其他經濟利益的手段,因此,直接和間接使用該開源代碼的用戶基數越大,開源項目對攻擊者的吸引力就越大。由于開源的特性,攻擊者會攻擊開源流程中的各個風險點以獲取收益。下面將介紹開源流程中的風險點。
3.1
惡意開源項目發布
攻擊者針對特殊用戶群體創建一個新的開源項目,新的項目中往往含有攻擊者針對目標受眾寫的惡意代碼,攻擊者還需要宣傳項目(公眾號文章、博客、甚至是郵件釣魚攻擊)以吸引受害者。
HVV期間曾出現過大量案例,GitHub出現針對某平臺紅隊開源利用代碼,實際內含針對使用者的惡意代碼,從而獲取到紅隊的信息。亦或項目內出現一些鏈接,經紅隊或藍隊訪問后,便掌握到紅隊或藍隊的出口IP。
3.2
與合法包混淆的包名(包名搶注)
該攻擊是在包儲存庫中部署與源包名相仿的名稱,插入惡意payload,引導、誤導下游用戶下載部署使用,有安全人員稱之為包名搶注。由于該類攻擊與正常名稱的項目資源是獨立的,不存在相互影響,因此攻擊代價往往比較低。
該類攻擊通常使用以下包名混淆手段:
- 后綴添加項目成熟度(dev|rc)、平臺兼容性(i386等);
- 對次序重新排列(test-vision-client和client-vision-test);
- 操作單詞分隔符(setup-tools和setuptools);
- 對字母排序(dajngo和django);
- 發布語言內置包的名稱(例如Pyhon中的subprocess);
- 品牌劫持:誤認為該包是可靠的(twilio-npm)
- 利用語義相似包名(request和requests)
3.3
開源平臺以及管理人員的安全風險
攻擊者可能是開源項目的維護者,也可能是參與項目的開發、構建或分發的第三方服務提供商的成員或者外包人員。這類人的最大共同點是對項目資源或基礎設施(如服務器等數據庫底層代碼存儲庫)有一定的訪問權限。Faker.js庫一直由Marak在維護,項目的增長與需求的增加并沒有換來對應收入的增長,沒有大公司愿意資助,Marak在NPM流行開發包colors提交了一個新版本,故意加入了一個死循環,導致使用colors的node.js服務器都出現了拒絕服務Denial of Service。
平臺的管理者管理不善也會對下游造成嚴重的風險。CodeCov是一款用于托管代碼測試報告和數據的在線平臺,2021年其Docker鏡像中泄露的憑證使攻擊者可以修改一個Bash腳本。當客戶下載并執行該腳本之后,客戶的憑證會被泄露,攻擊者進而可以訪問他們的Git倉庫。攻擊從當年的1月31日開始,而第一個客戶發現憑證遭受泄露時已是3個月之后,這意味著被入侵的軟件在長達數月的時間里正常與上下游對接。HashiCorp、Confluent等多個知名企業表示受到影響。
3.4
篡改合法的軟件包
這一類維度的攻擊面最為龐大,也是收益最大的一環,可以直接影響到該包的使用人群,使用者不會明顯發現任何異常、不會懷有戒心。以下將展開討論具體攻擊手段。
3.4.1
向合法開源包中注入惡意代碼
對于攻擊者而言,這是最有收益的手段,這將直接影響到下游的用戶,無論是使用源代碼還是使用預先構建的二進制文件(因為惡意代碼加載時間是在二進制文件構建分發之前)。
- 攻擊者可以扮演貢獻者的角色,使用假冒的合并請求將不成熟的漏洞,變成可以利用的漏洞,或者使用IDE的弱點來隱藏惡意代碼,例如通過Unicode控制字符隱藏或消除代碼差異。
- 攻擊者也可以通過社會工程學、維護系統的漏洞來接管項目維護者的賬戶,拿到修改代碼所需的特權,達到修改代碼的目的。
- 篡改項目也可以通過篡改VCS(Version Control System,版本控制系統)來實現,從而繞過項目已建立的貢獻工作流。通過漏洞或配置錯誤來改變最高權限用戶賬戶中相關VCS的配置。
3.4.2
在構建包的過程中注入惡意代碼
有些語言的包管理器(Maven或Java的Gradle),不是從VCS下載的開源項目源代碼,是從包存儲庫直接下載預構建的組件。惡意代碼的注入就發生在預構建的過程中。這種技術對于攻擊者來說是比較困難的,傳播也很有限。
攻擊者的手段大多分為兩種,一是運行惡意的構建任務,篡改多個項目構建任務的共享的系統資源。二是通過漏洞或配置錯誤,接管維護者賬戶從而篡改構建作業。
3.4.3
分發開源組件包的惡意版本
預構建代碼通常存儲在包存儲庫中,因此很容易去構建一個攜帶惡意代碼的二進制文件去其他途徑分發,比如CSDN等網站,或者緩存到代理中,或者通過CDN分發。
3.4.4
重定向資源
包獨立的名稱或URL是定位到開源組件包的途徑,當控制了這些途徑,便控制了使用者下載的資源。這時候攻擊者的目標是通過破壞合法項目外部的資源來使得受害者下載惡意包。這包括中間人(MITM)攻擊、DNS緩存投毒或直接在客戶端篡改合法URL。
存在一種特殊的攻擊手法,包管理器遵循一種(可配置的)解析策略來決定從何處下載包的某個版本,以及聯系多個存儲庫時的優先順序。攻擊者可以使用此類解析機制及其配置進行攻擊。
四. 開源軟件供應鏈中的法律問題
若是未按照開源許可證約定使用開源組件會引發潛在的法律糾紛。
許可證開源風險:一類許可證是若使用了此開源軟件,那么根據開源協議后續開發的軟件必須開源。最常見的許可證違反發生在GPL(GNU通用公共許可證)的使用中,一旦商用產品的組件依賴沾染到該許可證就必須開放該產品的源代碼。在過往的法律糾紛中,侵權行為的表現通常是商用產品依賴開源組件卻不遵循開源協議私自以閉源的形式出售、以及開發人員違規進行代碼復用。FSF曾狀告思科公司以Linksys品牌出售的各種產品違反了FSF擁有版權的程序許可條款,包括GCC、GNU Binutils 和GNU C庫。另一案例發生在近期,起因是在谷歌供職的Joshua Bloch直接從Oracle OpenJDK復制了9行代碼到谷歌的Android項目中,而Android項目沒有按GPL兼容的方式授權,此行為侵犯了Oracle的著作權,為此Oracle向谷歌索賠90億美元。
許可證修改風險[3]:React是前端開發中常用的開發框架,雖然開源但其背后由Facebook公司主導維護。2017年9月,在開發社區輿論壓力下,Facebook宣布React框架將由MIT許可證授權(原為BSD+專利許可證),這一宣布將影響包括React、Jest、Flow、Immutable、Fresco、React Native、Metro、Yoga等一眾開源軟件。Facebook做出此決定也是屬于輿論壓力之下的無奈之舉。原有的是BSD許可證+專利授權,意味著基于此開發的軟件項目在初期雖然可以正常使用。但是假如Facebook打算發布競品,并侵犯了你的軟件專利,由于BSD+專利授權許可,那么使用者將不能借此對Facebook發起侵犯軟件專利訴訟。
五. 開源軟件供應鏈安全防護措施
目前這兩年針對軟件供應鏈的產品逐漸完善,形成針對各個流程的安全防護手段,下面主要概述針對開源軟件供應鏈攻擊的防護措施。
5.1
最主要的措施
軟件材料清單(Software Bill of Materials, SBOM)必須由項目維護者生成、維護和詳細提供,理想情況下使用自動化軟件成分分析(Software Composition Analysis,SCA)工具,檢查所使用的組件,以及檢查是否含有惡意代碼或者漏洞組件。SBOM必須由包存儲庫安全地托管和分發,并由下游用戶仔細檢查他們的安全性、質量和許可證需求。
5.2
安全身份驗證
建議服務提供者提供多因素身份驗證(MFA)或實施強密碼策略,而項目維護人員應該遵循身份驗證標準,例如,在可用的情況下使用MFA,避免密碼重用,或保護敏感令牌。
5.3
對于項目維護者
維護人員應該進行仔細審查合并請求,或者為敏感的項目分支啟用分支保護規則,以避免惡意代碼貢獻。由于項目構建仍然可能發生在維護人員的工作站上,建議他們使用專用的構建服務。可以隔離構建步驟,這樣攻擊者就不能篡改構建完成的項目。
5.4
構建包應由使用者或參與者獨立完成
包的預購建工作不應該有下載時臨時構建,如果由包存儲庫實現,這將減少破壞項目構建的風險。如果由消費者實現,這將消除與第三方構建服務和包存儲庫妥協相關的所有風險。
5.5
使用代碼采取安全措施
在使用時可以通過隔離代碼和/或沙箱來減少惡意代碼執行的影響。使用相關檢測工具對代碼進行漏洞、惡意代碼檢測。
六. 總結與思考
列出的安全風險點有助于提高對開源軟件供應鏈威脅的認識,有助于確定給定利益相關者對供應鏈攻擊的暴露程度。下面是我的總結內容:
1. 軟件供應鏈安全的防護需要所有環節的人員去共同維護,攻擊者需要找到鏈條中單一弱點即可,而防御者需要覆蓋整個攻擊面。
2. 應提升所有環節人員的安全意識,從根本上解決安全問題。
3. 使用規范的軟件開發環節,使得代碼開發流程無懈可擊。
4. 完善安全審計工具,協助開發者解決自寫代碼、引入代碼中的安全問題。
5. 對所有引入代碼、開發人員不可信,對依賴的開源代碼、開發代碼多次掃描,防止投毒、漏洞的引入,甚至是內部人員的惡意攻擊。
6. 使用者應從官網下載代碼,并根據自己需求,審查許可信息。