Go是如何緩解供應(yīng)鏈攻擊的
這些年來(lái),關(guān)于軟件供應(yīng)鏈的安全問(wèn)題頻發(fā),軟件供應(yīng)鏈已然成為IT安全領(lǐng)域的一個(gè)熱點(diǎn),在前不久的《聊聊Go語(yǔ)言的軟件供應(yīng)鏈安全》[1]撰寫(xiě)的文章《How Go Mitigates Supply Chain Attacks》[2],系統(tǒng)總結(jié)了Go語(yǔ)言應(yīng)對(duì)軟件供應(yīng)鏈方面攻擊的“防護(hù)秘笈”。筆者覺(jué)得文章中提到的這些點(diǎn)是每個(gè)Gopher都應(yīng)該知道的必備知識(shí),于是這里將文章做簡(jiǎn)單翻譯,供大家參考。
現(xiàn)代軟件工程基于相互協(xié)作,并以重用開(kāi)源軟件為基礎(chǔ)。但這也使軟件項(xiàng)目成為了供應(yīng)鏈攻擊的目標(biāo),攻擊方式就是破壞軟件項(xiàng)目的依賴(lài)(dependencies)。
盡管知道這些,為了完成項(xiàng)目,我們需要依賴(lài),我們會(huì)采取一些流程或技術(shù)措施在項(xiàng)目與依賴(lài)之間建立一種信任關(guān)系。好在,Go的工具鏈與設(shè)計(jì)可以幫助我們降低各個(gè)階段的風(fēng)險(xiǎn)。
所有構(gòu)建都是被“鎖定(locked)”的
外部世界的變化,比如項(xiàng)目的某個(gè)依賴(lài)發(fā)布了一個(gè)新版本,是不會(huì)影響到Go的構(gòu)建的。
與其他大多數(shù)軟件包管理器(package manager)所使用的配置文件不同,Go module沒(méi)有將存儲(chǔ)約束列表的文件和鎖定特定版本的lock文件分開(kāi)管理,對(duì)任何Go構(gòu)建作出貢獻(xiàn)的每個(gè)依賴(lài)項(xiàng)的版本完全由main module的go.mod文件決定。
從Go 1.16版本[3]。唯一可以改變go.mod文件(當(dāng)然構(gòu)建也會(huì)隨之改變)的命令是go get和go mod tidy。這兩個(gè)命令通常不會(huì)自動(dòng)運(yùn)行或在CI中運(yùn)行,所以對(duì)依賴(lài)樹(shù)的改變必須是主觀故意的,我們可以在操作前對(duì)這種改變做代碼評(píng)審。
這對(duì)安全非常重要,因?yàn)楫?dāng)CI系統(tǒng)或新機(jī)器運(yùn)行時(shí),簽入(checked-in)的源碼是最終的和完整的,代碼將說(shuō)明什么會(huì)被構(gòu)建,第三方?jīng)]有辦法影響它。
此外,當(dāng)用go get添加新依賴(lài)時(shí),由于最小版本選擇[4]的存在,它的傳遞依賴(lài)(transitive dependencies)的指定版本,不是最新版本,也會(huì)被添加到go.mod文件中。同樣的情況也發(fā)生在調(diào)用go install example.com/cmd/devtoolx@latest 的情況下,在某些生態(tài)系統(tǒng)中,同樣的構(gòu)建發(fā)生時(shí)會(huì)繞過(guò)“已鎖定”的版本(譯注:去獲取依賴(lài)的最新版本)。但在Go中,example.com/cmd/devtoolx的最新版本將被獲取,但其所有的依賴(lài)項(xiàng)的版本將取決于其go.mod文件中的設(shè)置。
如果一個(gè)module被破壞,新的惡意版本被發(fā)布,沒(méi)有人會(huì)受到影響,直到他們明確地更新該依賴(lài)關(guān)系,這種方式為gopher提供了審查變化的機(jī)會(huì),并為生態(tài)系統(tǒng)提供時(shí)間來(lái)檢測(cè)該事件會(huì)引發(fā)的影響。
版本內(nèi)容永不改變
確保第三方不能影響構(gòu)建的另一個(gè)關(guān)鍵屬性是,module版本的內(nèi)容是不可改變的。如果一個(gè)破壞某依賴(lài)項(xiàng)的攻擊者可以重新上傳該依賴(lài)項(xiàng)的一個(gè)現(xiàn)有的版本,那么他就可以自動(dòng)破壞所有依賴(lài)該依賴(lài)項(xiàng)的項(xiàng)目。
這就是go.sum文件[5]的作用。它包含了對(duì)構(gòu)建有貢獻(xiàn)的每個(gè)依賴(lài)項(xiàng)的加密哈希值的列表。同樣,一個(gè)不完整的go.sum會(huì)導(dǎo)致一個(gè)錯(cuò)誤,并且只有g(shù)o get和go mod tidy會(huì)修改它,所以對(duì)它的任何修改都會(huì)伴隨著一個(gè)主觀故意的依賴(lài)性的改變。其他的構(gòu)建將被保證有一套完整的校驗(yàn)和。
這是大多數(shù)lock文件的一個(gè)共同特征。但Go通過(guò)校驗(yàn)和數(shù)據(jù)庫(kù)(簡(jiǎn)稱(chēng)sumdb)[6]領(lǐng)先了一步,sumdb是一個(gè)全局性的、僅可附加的(append)、加密驗(yàn)證的go.sum條目列表。當(dāng)go get需要在go.sum文件中添加一個(gè)條目時(shí),它從sumdb中獲取該條目,并對(duì)sumdb的完整性進(jìn)行加密證明。這不僅確保了某一module的每一次構(gòu)建都使用相同的依賴(lài),而且確保了每一個(gè)module都使用相同的依賴(lài)內(nèi)容。
sumdb使那些試圖用修改過(guò)的(例如放置后門(mén)的)源碼來(lái)攻擊特定依賴(lài)項(xiàng)變?yōu)椴豢赡埽踔凉雀枳约哼\(yùn)維的Go基礎(chǔ)設(shè)施也做不到。
它將保證你使用的代碼與其他使用例如example.com/modulex v1.9.2的人所使用的代碼完全相同,并且已經(jīng)過(guò)審查。
最后,我最喜歡sumdb的特點(diǎn):它不需要module作者的任何密鑰管理,而且它與Go module的非中心化特性無(wú)縫連接。
VCS是真相之源
大多數(shù)項(xiàng)目是通過(guò)一些版本控制系統(tǒng)(VCS)開(kāi)發(fā)的。在其他生態(tài)系統(tǒng)中,這些項(xiàng)目還需要被再次上傳到中心軟件包庫(kù)(譯注:比如js生態(tài)中的npm)。這意味著有兩個(gè)賬戶(hù)可能被入侵,一個(gè)是VCS主機(jī),另一個(gè)是中心軟件包庫(kù)。對(duì)后者的攻擊使用得更少,也更容易被忽視。這也意味著在上傳到中心倉(cāng)庫(kù)的版本中更容易隱藏惡意代碼,尤其是當(dāng)源碼作為上傳的一部分被例行修改時(shí),比如說(shuō)將其最小化(譯注:比如js代碼的壓縮)。
在Go中,不存在中心包庫(kù)賬戶(hù)這樣的東西。包的導(dǎo)入路徑包含了go mod download所需要的信息,以便go命令直接從VCS中獲取其module,vcs上的標(biāo)簽定義了module的版本。
我們確實(shí)有Go Module Mirror[7],但那只是一個(gè)代理。module作者不需要注冊(cè)賬戶(hù),也不需要向代理上傳版本。代理使用與go工具鏈相同的邏輯(事實(shí)上,代理運(yùn)行g(shù)o module download)來(lái)獲取和緩存一個(gè)版本。由于校驗(yàn)數(shù)據(jù)庫(kù)保證一個(gè)給定的module版本只能有一個(gè)源碼樹(shù),每個(gè)使用代理的人都會(huì)看到從代理獲取的結(jié)果與繞過(guò)代理直接從VCS獲取的結(jié)果是相同的。(如果該版本在VCS中不再可用,或者其內(nèi)容發(fā)生了變化,直接獲取將導(dǎo)致錯(cuò)誤,而從代理獲取可能仍然有效,提高了可用性并保護(hù)生態(tài)系統(tǒng)免受["左鍵"問(wèn)題](https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm ""左鍵"問(wèn)題")的影響)。
在客戶(hù)端運(yùn)行VCS工具會(huì)暴露出一個(gè)相當(dāng)大的攻擊面。這也是Go module mirror的另一個(gè)作用:代理上的Go工具在一個(gè)強(qiáng)大的沙盒內(nèi)運(yùn)行,并被配置為支持所有的VCS工具,而默認(rèn)的是只支持兩個(gè)主要的VCS系統(tǒng)(git和Mercurial)[8]。任何使用代理的人仍然可以獲取使用非默認(rèn)的VCS系統(tǒng)發(fā)布的代碼,但攻擊者在大多數(shù)安裝中無(wú)法接觸到這些代碼。
僅構(gòu)建代碼,但并不會(huì)執(zhí)行它
Go工具鏈的一個(gè)明確的安全設(shè)計(jì)目標(biāo)是,無(wú)論是獲取還是構(gòu)建代碼,都不會(huì)讓代碼執(zhí)行,無(wú)論代碼是否是不被信任的和惡意的。這與其他大多數(shù)生態(tài)系統(tǒng)不同,許多生態(tài)系統(tǒng)在獲取軟件包時(shí)對(duì)運(yùn)行代碼提供了first-class的支持。這些"post-install"的鉤子在過(guò)去被用作一種最方便的攻擊方式:通過(guò)受到攻擊的依賴(lài)攻擊開(kāi)發(fā)者的機(jī)器,并通過(guò)module作者進(jìn)行蠕蟲(chóng)攻擊[9]。
公平地說(shuō),如果你要獲取一些代碼,往往會(huì)在不久之后執(zhí)行,要么作為開(kāi)發(fā)者機(jī)器上的測(cè)試的一部分,要么作為生產(chǎn)中的二進(jìn)制文件的一部分,所以缺乏post-install鉤子只會(huì)減緩攻擊者。(在構(gòu)建過(guò)程中沒(méi)有安全邊界:任何有助于構(gòu)建的軟件包都可以定義一個(gè)init函數(shù))。然而,它可以成為一個(gè)有意義的風(fēng)險(xiǎn)緩解措施,因?yàn)槟憧赡苷趫?zhí)行一個(gè)二進(jìn)制文件或測(cè)試一個(gè)包,而這個(gè)包只使用module依賴(lài)的一個(gè)子集。例如,如果你在macOS上構(gòu)建并執(zhí)行example.com/cmd/devtoolx,那么針對(duì)Windows的依賴(lài)或example.com/cmd/othertool的依賴(lài)就不可能危害到你的機(jī)器。
在Go中,沒(méi)有為特定構(gòu)建提供代碼的module對(duì)構(gòu)建沒(méi)有安全影響(譯注:得益于Go 1.17引入的module依賴(lài)圖修剪)。
"一點(diǎn)復(fù)制比一點(diǎn)依賴(lài)性好"
在Go生態(tài)系統(tǒng)中,最后一個(gè)可能也是最重要的軟件供應(yīng)鏈風(fēng)險(xiǎn)緩解措施,可能也是最沒(méi)有技術(shù)含量的一個(gè):Go有一種拒絕大型依賴(lài)樹(shù)的文化,寧可復(fù)制一點(diǎn)也不愿意增加新的依賴(lài)關(guān)系。這可以追溯到Go的一個(gè)諺語(yǔ):["一點(diǎn)復(fù)制比一點(diǎn)依賴(lài)性好"](https://youtube.com/clip/UgkxWCEmMJFW0-TvSMzcMEAHZcpt2FsVXP65 ""一點(diǎn)復(fù)制比一點(diǎn)依賴(lài)性好"")。"零依賴(lài)"的標(biāo)簽總是被高質(zhì)量的可重復(fù)使用的Go module所自豪地佩戴。如果你發(fā)現(xiàn)自己需要一個(gè)這樣的庫(kù),你很可能會(huì)發(fā)現(xiàn)它不會(huì)導(dǎo)致你依賴(lài)其他作者和所有者的幾十個(gè)module。
豐富的標(biāo)準(zhǔn)庫(kù)和附加module(golang.org/x/...的module)也使之成為可能,這些module提供了常用的高級(jí)構(gòu)建模塊,如HTTP棧、TLS庫(kù)、JSON編碼等。
所有這些意味著只需少量的依賴(lài)關(guān)系就可以建立豐富、復(fù)雜的應(yīng)用程序。無(wú)論工具有多好,它都不能消除重復(fù)使用代碼的風(fēng)險(xiǎn),所以最有力的緩解措施永遠(yuǎn)是一個(gè)小的依賴(lài)樹(shù)。
參考資料
《聊聊Go語(yǔ)言的軟件供應(yīng)鏈安全》:?https://mp.weixin.qq.com/s/qo6wiRIJHyO5vgAJrQFfuw
[2]?《How Go Mitigates Supply Chain Attacks》:?https://go.dev/blog/supply-chain
[3]?Go 1.16版本:?https://mp.weixin.qq.com/s/UPNn4G_m0zfvJgWxEVl_Tw
[4]?最小版本選擇:?https://go.dev/ref/mod#minimal-version-selection
[5]?go.sum文件:?https://go.dev/ref/mod#go-sum-files
[6]?校驗(yàn)和數(shù)據(jù)庫(kù)(簡(jiǎn)稱(chēng)sumdb):?https://go.dev/ref/mod#checksum-database
[7]?Go Module Mirror:?https://go.dev/blog/module-mirror-launch
[8]?默認(rèn)的是只支持兩個(gè)主要的VCS系統(tǒng)(git和Mercurial):?https://go.dev/ref/mod#vcs-govcs
[9]?蠕蟲(chóng)攻擊:?https://en.wikipedia.org/wiki/Computer_worm
[10]?“Gopher部落”知識(shí)星球:?https://wx.zsxq.com/dweb2/index/group/51284458844544
[11]?我愛(ài)發(fā)短信:?https://51smspush.com/
推薦閱讀
