天天看點

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

為代碼資産管理者提供一個審視安全的基本架構

本文作者:王振威 - CODING 研發總監 CODING 創始團隊成員之一,多年系統軟體開發經驗,擅長 Linux,Golang,Java,Ruby,Docker 等技術領域。近兩年來一直在 CODING 從事系統架構和運維工作。

不同類型的企業資産有不同的管理辦法,但守護資産的安全性無一例外都是重中之重,但對如何保障代碼資産安全并沒有形成統一認知。本文将就“代碼資産的安全性”這一話題展開全面的闡述,嘗試從代碼管理的生命周期進行全鍊路分析,讀者可以據此來審視自己企業的代碼資産安全。

代碼資産安全不等于資訊安全,這是很容易了解的。整個企業的資訊系統組成不僅僅是代碼資産,甚至可以說大多數情況下不涉及代碼資産。企業的資訊系統往往由基礎計算設施、網絡平台、軟體、資料庫等方面組成。資訊安全重點是關注上述資訊設施在投産之後運作過程中的安全問題。而大多數軟體運作的程式包是經由源代碼編譯的結果,跟源代碼本身是分割開來的。資訊安全關注的方面更為全面,代碼資産安全隻是其中的一部分,而且往往不是最為關注的一部分。

代碼資産安全不等于代碼安全,這不太容易了解。代碼安全往往指代代碼本身的安全性,如代碼中是否有遠端過程執行漏洞,注入漏洞等等。而代碼資産安全是一個管理概念,強調管理過程的安全,而非代碼本身安全,例如某研究機構需要研究某種計算機病毒,他們需要在源碼庫中存放對應病毒的源碼。這病毒的源碼就是這個機構的重要資産。

代碼管理系統不審視源碼中的漏洞或者惡意行為,而是必須忠實地确儲存儲的代碼的原始檔案。

代碼資産管理的核心是代碼倉庫。倉庫裡存放着企業的全部代碼,配置檔案以及全部曆史版本。守護代碼資産安全的核心就是圍繞代碼倉庫的三個關鍵環節建構起全鍊路的安全能力,這三個環節分别是檢入,存儲和檢出。

檢入可以了解為開發者在開發環境上編輯好代碼,并且把代碼傳送到代碼倉庫的過程。這個環節關注兩個方面,分别是機密性和完整性。

機密性是指開發者把開發環境中的代碼檢入代碼倉庫的過程不被第三方竊取,一般通過傳輸過程加密來實作。Git 代碼倉庫最常用的是 HTTPS 和 SSH 傳輸協定。

HTTPS 協定是通過 HTTP 協定加上傳輸層安全協定(TLS)實作的。HTTP 協定是明文傳輸協定,這意味着如果沒有 TLS,網絡節點中的路由裝置都可以輕松竊取代碼。TLS 可以在 TCP 協定之上建立雙向加密能力,配合 HTTP 協定上就是 HTTPS。HTTPS 用戶端和服務端先通過非對稱加密協商加密算法和密鑰,再使用協商的算法和密鑰來進行對稱加密傳輸。本文不涉及具體算法的安全性介紹,不過随着密碼學的發展,算法在與時俱進,我們可以認為加密算法本身是安全的。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

然而這一過程并不完備,攻擊者可以制作中間伺服器,使得用戶端在發起連接配接的時候誤連接配接了中間伺服器,進而跟這個中間伺服器進行加密通信。這将導緻即便是加密傳輸,但最終還是會被惡意伺服器竊取,這就形成了中間人攻擊。

行業推出了 CA(證書授權機構)機制應對此問題,即伺服器在提供加密傳輸服務前,要把自己的公鑰和服務的域名綁定,并且在全球公信的 CA 處登記。這樣一來,HTTPS 用戶端在嘗試建立加密連結的時候,會要求伺服器出示 CA 簽發的證書,用戶端可以使用預安裝在作業系統或者浏覽器内的 CA 公鑰進行驗證,确認伺服器對域名的所有權,這樣一來就可以確定不會有中間人攻擊。有行業公信力 CA,也有企業内部 CA,而後者需要在用戶端安裝企業内部 CA 的證書檔案。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

知名安全機構 Qualys 可以線上對 HTTPS 伺服器進行 SSL/TLS 多方面的報告評估,如下圖為兩家國内雲計算公司推出的代碼托管伺服器的評估:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全
CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

HTTPS 雖然解決了傳輸安全,但在認證使用者身份這裡,Git 代碼倉庫還是依賴 Basic Auth 機制來實作。Git 代碼倉庫會要求 HTTPS 用戶端提供賬号密碼,并附在請求體中一并傳輸給伺服器,由伺服器來确認操作者身份。在傳輸過程中,賬号和密碼是被 TLS 一并加密傳輸的,我們不必擔心傳輸過程的密碼洩露問題。但開發者通常為了不必每次操作都輸入賬号密碼,會讓電腦記住密碼,如果不妥善處理,可能會導緻洩露。這裡重點是一定不能把賬号密碼拼接在遠端倉庫通路位址裡面,正确的做法是使用 Git 在各種作業系統下的 憑據管理器,如 macOS 是使用鑰匙串管理,Windows 是使用 Git Credential Manager for Windows 來進行管理。

SSH 是一種常用于遠端管理 Linux/Unix 伺服器的安全加密協定,其功能非常多樣。以 Git 為基礎的代碼托管也常使用這個協定進行加密代碼傳輸。使用者提前把自己的公鑰檔案配置在伺服器上後,可以在後續的傳輸過程中确認身份。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

SSH 使用非對稱加密(使用者的公鑰)确認身份,用對稱加密傳輸資料。跟 HTTPS 不同的是,SSH 協定無法指定域名,是以無法引入 CA 機制來防止中間人攻擊。

但 SSH 用戶端在與未知伺服器進行連接配接時,會提示伺服器的公鑰指紋資訊,使用者應當對比服務供應商官方提供的公鑰公告和指令行提示資訊來确認伺服器身份,確定不被中間人攻擊。

如圖展示騰訊雲 CODING SSH 伺服器的公鑰指紋公示:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

如圖所示,SSH 用戶端嘗試連接配接伺服器時給出的伺服器公鑰指紋确認:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

在使用者确認身份(輸入 yes 并按下回車)後,SSH 用戶端會把伺服器的公鑰資訊記錄在 ~/.ssh/known_hosts 中,下次即可直接連接配接,不再詢問。

代碼的傳輸要使用雙向加密協定,HTTPS 和 SSH 都可以

HTTPS 協定需要關注伺服器的證書簽發方(CA)的權威性

HTTPS 協定需要關注用戶端是否安裝了不受信任的 CA 檔案(防止 CA 欺詐)

使用 Git 憑據管理器保管 Git HTTPS 協定的賬号密碼

SSH 協定在使用的時候需要仔細比對伺服器提供的公鑰指紋跟服務提供商公告的公鑰指紋是否完全一緻,防止中間人攻擊

用戶端需要注意防止攻擊者惡意篡改 ~/.ssh/known_hosts 檔案内容或者 SSH 的用戶端配置(可以通過忽略伺服器公鑰信任機制)

妥善保管 SSH 私鑰檔案(往往存放于 ~/.ssh/id_rsa),如 Linux 下確定此檔案的權限是 400 等,防止他們讀取

代碼檢入的完整性包含兩個方面:

開發者一次送出的代碼變動是否完整(内容不被篡改)

某次送出是否确為某開發者做出的變動(不被冒名頂替)

以 Git 為例子,這個代碼版本控制軟體已經從内生機制上確定了内容不被篡改。Git 采用一種類 Merkel 哈希樹的機制來實作分層校驗。

哈希是一種把任意資料映射成等長資料的算法,且不可逆。雜湊演算法有的特點是原始資料發生一點變化,映射的結果會産生較大變化,而且這一變化毫無規律。映射後的等長的資料被稱為指紋。

雜湊演算法非常适合用來快速比較兩段資料是否完全一緻(指紋一緻幾乎可以推斷原文一緻)。在我們上文中提到的對比 SSH 伺服器出示的公鑰指紋,和服務提供商公告的指紋就是這種原理的應用。

Merkel 哈希樹:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

Git 對倉庫中的每一個檔案内容和其基本資訊整合進行哈希。會将一個目錄樹下的所有檔案路徑和檔案哈希值組合再哈希形成目錄樹的哈希。會把目錄樹和送出資訊組合再哈希,此哈希結果就是 Git 的版本号。這意味着每次送出都産生一個完全不同的版本号,版本号即哈希。在給定一個版本号,我們可以認為這個版本背後對應的全部檔案内容,曆史記錄,送出資訊,目錄結構都是完全一緻的。對于确定的版本号就沒有篡改的可能性。

雜湊演算法小機率會産生沖突(同一個指紋對應多個不同原始資料的情況),這時可能導緻一緻性校驗失效。是以雜湊演算法也在與時俱進,如當下 MD5 算法已經幾乎過時,Git 目前正在使用 SHA1 算法,未來可能會更新到更為安全的 SHA256 算法。

如圖展示 Git 中的某個目錄樹的内容資訊:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

即便開發者自己送出的版本經過 Git 的層層哈希,可以確定内容不被惡意篡改,但仍然有被冒名頂替的危險。

因為 Git 在送出過程不需要驗證使用者身份,而且送出可以被不同的人在各種傳輸過程中傳輸和展示。設想攻擊者冒充公司員工制造一個送出,卻被公司其他員工認為是公司内部人士會有多可怕。目前基于 Git,業界的普遍做法是引入 GPG 簽名機制。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

GPG 是基于非對稱加密算法的一個應用,其原理是使用私鑰處理一段資訊,得到一段新的資訊,這段新的資訊隻能由私鑰生成,而且可以使用對應的公鑰來識别這段新的資訊的生成來源,這段新的資訊就被稱為數字簽名。

簡單來說,資訊釋出者使用自己的私鑰(私人印章)對要釋出的資訊(待簽名檔案)進行簽名,并且把原始檔案和數字簽名一并發送給使用方。使用方持有釋出方的公鑰,對收到的數字簽名和原始檔案進行校驗就可以确認确實是釋出方發出的,未被冒名頂替。這類似給要釋出的資訊蓋了個章。

如圖展示 Git 中某個送出被開發者添加 GPG 簽名的效果:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

Git 本身的哈希機制可確定内容不被篡改

使用 GPG 為送出簽名可防止冒名頂替

伺服器端要校驗 Git 送出郵箱聲明和 GPG 簽名

存儲安全是指當代碼被檢入到代碼倉庫後,如何保證資料的機密性,完整性和可用性。抛開基礎設施的安全性不談,對于代碼存儲來說,資料往往由資料庫資料和代碼庫檔案組成,這裡重點讨論代碼檔案存儲安全問題。

代碼倉庫中的代碼大多直接存放于作業系統的磁盤中,在伺服器軟體進行讀寫操作的時候,不涉及網絡傳輸的機密性風險,但直接寫入磁盤上的檔案在未做控制的情況下,往往可以被作業系統上的很多不相關程序随意讀寫,這些非預期的代碼讀寫會造成額外的風險。

一種做法是去控制每一個檔案的讀寫權限,如統一設定為 600,另一種做法是幹脆隻允許伺服器上運作一個業務程序,實作作業系統級别隔離。

容器技術提供了一種良好的隔離程序方案:如在 Kubernetes 體系下,代碼倉庫存儲在 PV 上,并隻被挂載進代碼倉庫的應用容器内讀寫,而且基于容器的排程和彈性特性可以較好的支援高可用并避免資源浪費。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

我們知道 Git 本身會通過哈希校驗機制來確定倉庫的完整性,但前提是倉庫檔案是完備的。如果倉庫的檔案丢失或者損壞,Git 的哈希校驗也将無法工作。資料的完整性有很多種解決方案,最常見的冷備,半實時備份,實時備份,磁盤快照等方案都是為了確定檔案在丢失或者損壞的時候可以找回,來確定倉庫的完整性的。不過總的來說,備份往往是事後的恢複手段,無法實作即時的自愈,最終依據備份機制來進行資料修複往往會影響可用性。

雖然業界沒有針對代碼倉庫的通用高可用方案,但資料庫主從政策和 RAID 機制是兩個可以參考的做法,這裡來做下簡要介紹。

資料庫主從政策,一種做法是資料寫入主庫,從庫自動增量同步資料。當主庫發生故障時,從庫自動替代。代碼存儲類似,可以把存儲節點分為主節點和從節點。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

RAID 機制是一種磁盤分片存儲的備援機制,有多種做法,如 RAID5,分片存儲,并存儲一份校驗資訊,當任意一塊磁盤壞掉,可以通過校驗資訊來複原資料。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

騰訊雲 CODING DevOps 在這方面進行了深入研究,并結合了主從和 RAID 的思路,實作了針對代碼倉庫的高可用政策,可妥善保障倉庫的完整性。

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

如圖所示,對于 D 倉庫來說,他的主倉庫 D(m) 存放于第二個節點,他的從倉庫 D(s) 存放于第一個節點(實質上還可以設定更多從倉庫,這裡為了圖示友善,隻顯示了一個)。這樣的設計讓各個節點都可以不閑置計算資源,而且任意一個節點出現損壞都可以快速恢複。

代碼檢出後才能使用,而檢出也涉及傳輸機密性問題,這點與檢入部分沒有差別。而對于 Git 倉庫來說,檢出環節的倉庫完整性會由 Git 的哈希校驗機制保證,也不會有太大問題。檢出環節的安全問題往往是因為不合适的權限政策和密鑰管理導緻代碼洩露。

企業内部代碼通常有如下四個場景:

檢出開發

閱讀評審

自動執行(CI,自動化測試等)

管理審計

需要區分開發者能讀寫的權限範圍,保護好關鍵資源和密鑰,按如下原則:

按照業務、元件等進行分門别類的存放,倉庫隔離

根據所處的部門群組織關系配置倉庫的權限

為分支設定讀寫權限,隻允許有權限的成員寫入

使用檔案鎖定方式保護敏感檔案不被誤修改

統一傳輸協定,如隻允許 HTTPS 或者 SSH

為個人密碼,令牌,公鑰等設定有限期

審計密碼,令牌,公鑰等的使用記錄

為目錄設定讀寫權限,隻允許指定開發者讀取或者寫入某些目錄

禁止強制推送政策,防止代碼被回退

如圖所示,設定倉庫内的目錄權限:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

訴求是看源碼和輔助資訊,并做出自己的評審結果,不涉及寫入代碼,按如下原則:

區分讀寫和隻讀成員群體,禁用後者的寫入權限

區分深入評審和輕量級評審,禁用後者的代碼檢出權限,隻允許其 Web 頁面檢視源碼

使用 CODEOWNERS 機制自動指定評審成員

如圖所示,設定倉庫的 CODEOWNERS:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

自動檢出,檢出行為背後不對應一個人,不涉及代碼寫回,按如下原則:

禁止成員把自己的密碼,令牌,密鑰用于自動執行

使用項目/倉庫令牌,部署公鑰機制確定令牌和密鑰隻對指定倉庫有權限

為不同場景設定專用的令牌,不得混用,也不得用于其他用途

為令牌,公鑰等設定有效期

為令牌,公鑰等設定禁止寫入權限

審計令牌,公鑰等的使用記錄

如圖所示,設定令牌的權限和有效期:

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

這種場景是非技術人員希望了解倉庫統計資訊,活躍情況,了解研發過程進度等,按如下原則:

給成員開放所管轄的倉庫清單和倉庫詳情的 Web 頁通路權限

禁止成員使用 HTTPS/SSH 協定把源碼檢出到本地

禁止成員在網頁端下載下傳源碼包

如圖所示,設定禁止倉庫寫入等權限

CODING 代碼資産安全系列之 —— 建構全鍊路安全能力,守護代碼資産安全

代碼資産管理是個體系化的工程,這個過程中的安全性不是某個單點可以完全保障的,需要從檢入,存儲,檢出三個環節對全鍊條進行風險分析。很多企業在這些方面很重視,但聚焦錯了方向,可能付出了很大努力,但實質上依然冒着代碼資産的丢失和洩露的巨大風險。希望此文可以幫助企業正視代碼資産安全,為代碼資産管理者提供一個審視安全的基本架構。

讓 CODING 為您的代碼資産保駕護航

繼續閱讀